Комментарии 34
про управление форматированием в C странный заход. Там все есть, что надо.
А как их не использовать совместно? Распространенный lvgl написан на C, gtk - снова C, и так куда не плюнь - везде пересечения...
Прошу не серчать, я не програмист, я конструктор, но сообщество ИТ специфично и интересно (да, это как отдушина).
Суть вопроса (ситуации):
Поскольку согласен, что это разные языки и мешать их не самая лучшая практика, но!
Столкнулся с тем, что при написании библиотеки бинарного хранения конфиг файлов используя C++ уперся в стену:
- В С++ решение выделить память С ВЫРАВНИВАЕМ и последующим удалением мягко скажем многословней чем в СИ.
- Само выделение очень вариативно и по синтаксису и по способам, это сбивает с толку новичка
- Даже выделив её покапаться изрядно в ней (перемещения, наложения и пр.) средствами C++ используя только его и std:: порождает ощущение танцев очень похожих на Си, но с прелюдией.
Да, есть обёртки над СИшными операциями с блоками памяти, но я не увидел какого то нового уровня обеспечения безопасности при большей многословности кода.
Буду признателен:
Лаконичному примеру в C++ который алоцирует с выравниванием память и совершает например запись люб. значения по люб. по адресу и в добавок выполняет аналог memmove с наложением. Но сугубо в рамках C++ и std::
Спасибо!
А почему в C++ выделить память сложнее с выравниванием? Есть же T *PTR = new (std::align_val_t(ALIGN)) T[ARRAY_SIZE]
(для удаления delete[] (std::align_val_t(ALIGN), PTR)
, также есть версия без []
) или std::aligned_alloc
(для удаления std::free
). Более того, вы просили пример, вот он: https://pastebin.com/TPHftGiA (да, я использовал rand()
, который типа C, -- но это просто для заполнения массива, то, что вы просили, сделано средствами C++).
Действительно, похоже на код в стиле C++, однако я не очень понимаю, чем тот же оператор new так сильно отличается от вызова malloc из std библиотеки C. Хотя отличия несомненно есть, это не вносит существенной разницы. В частности, в вашем примере оператор new - это функция malloc, сказанная другими словами. Да и в случае перевыделения памяти в C++ всё равно неизбежно приходится использовать realloc. А, простите, из-за того, что всю стандартную библиотеку языка C поставили под неймспейс std, считать код подогнанным под идеологию C++, ну, лично для меня, не очень корректно.
Можете уточнить что значит бинарное хранение конфиг файлов и почему нужно именно выравнивание?
что значит бинарное хранение конфиг файлов
берем структуру, и пишем ее как есть в файл/eeprom. Обычно актуально для маленьких микроконтроллеров, где сериализация будет дорогой штукой по ресурсам. Ну а чтобы это занимало минимум места, выравниваем побайтово.
Вопрос только в том, причем тут плюсы... Обычно в таких штуках чистый С.
Непонятно причём здесь выравнивание, достаточно добавить атрибут, чтобы лишних паддингов не было:
struct __attribute__((packed)) Foo {
char a;
int c;
char b;
};
спасибо, просто мне надо было уточнить о чем речь + я попутно посмотрел хотябы на своём коде cache-misses в моём коде (без контроллеров с задержкой 60 мс программа даёт 39процентов, если выключить задержку вообще 1 процент, ) .
насчет примера тоже спасибо. приложу свой пример (пример к тому что файл это набор char) там не возьмусь прям советовать как лучше
unordered_map<string,vector<pair<int,vector<uint8_t>>>> worker;
...
void serialize()
{
ofstream file;
file.open("assets.bin",ios::binary);
int s=worker.size();
//cout << s <<" 1"<< endl;
file.seekp(0);
file.write(reinterpret_cast<const char*>(&s),sizeof(s));
for(auto a:worker)
{
const char* b=a.first.data();
int slen=a.first.size();
int n1=a.second.size();
file.write(reinterpret_cast<const char*>(b),sizeof(char)*40);
file.write(reinterpret_cast<char*>(&n1),sizeof(n1));
//cout << b <<" 3"<< endl;
std::vector<std::pair<int,vector<uint8_t>>> l=a.second;
for(auto& c:l)
{
int k=c.first;
vector<uint8_t>t=c.second;
//cout << k <<" 2"<< endl;
file.write(reinterpret_cast<const char*>(&k),sizeof(k));
writeVector(file,t);
}
}
file.close();
}
//сразу файлами тоесть на входе факторка дающая указатели
//или загрузил все файлы и через факторку дал указатели,
//где в программе удалил и по новой единственный нюанс не знаю
//как на контроллерах на андроид как я понял надо кинуть в JNI ifstream
//я заюзал SDL3 уже перегруженое чтение
вряд ли выравнивание вам нужно больше чем 16, поэтому
new char[N];
Язык C достаточно простой и эффективный. На нем можно писать простые функции и эффективные решения. На нем много библиотек. Если вы делаете ошибки в C - рано увеличивать сложность и переходить к C++. И совет не используйте выделение памяти в стиле С в C++ потому что можно выделить что-то в стеке... Это очень странно.
Каша какая-то. Нет ничего плохого в использовании готового C кода в плюсах. А вот за что надо руки отбивать - за программирование в сишном стиле на плюсах. Ну и как-то по детски написано. Что ж будет, когда автор откроет для себя stdcall и cdecl)
Здравое зерно, безусловно, есть. Я думаю, всем будет лучше, если люди, которым не нравятся сишные корни, отселятся уже в какой-нибудь отдельный пузырь. Жаль, что этого не случилось сразу после появления «Си с классами».
Есть намного лучшее изложение этого тезиса.
https://youtu.be/YnWhqhNdYyk
А знаете, что ещё безопаснее, чем Си? Rust /s
Тема манглинга немного не соответствует названию статьи. Есть мнение, что у каждой хорошей С++ библиотеки должен быть С-интерфейс (см. в конце этой статьи), как раз потому что в C нет манлирования.
На мой взгляд, уместнее было бы рассказать о разнице в приведении типов (как например здесь) или о поведении C-cast в C++ коде.
На правах оффтопа: вы же игровой движок разрабатываете, было бы гораздо интереснее прочитать от вас кейсы по этой теме причем любой. Например, как 3D редактор в него интегрировали. Гайджины и Playrix в своих блогах раньше хорошие статьи размещали по теме.
На правах шутки:
Тут один известный в геймдеве мужик в очках рассказывает, как он пишет на C++ сейчас (см. с отметки 1:55)
cin и cout весьма медленные по сравнению с scanf и printf. Так что если нужно выжимать производительность, то совет из статьи так себе.
Если правильно использовать (std::ios::sync_with_stdio(false); std::cin.tie(nullptr);
и не пользоваться std::endl
(он сбрасывает буффер вывода, вместо него лучше использовать '\n'
-- это не сбрасывает буффер вывода), то std::cin и std::cout будут быстрее. Другое дело, что в Microsoft Visual C++ не поддерживается std::ios::sync_with_stdio(false);
(ну как бы такая функция есть, но она ничего не делает, т. е. std::cin и std::cout не ускоряются от нее)... Но даже так в C++ стандартный ввод-вывод все еще остается достаточно медленным.
Нужно просто использовать std::print ;)
Автор статьи скорее расписался в недостаточной квалификации нежели привел доводы.
С и С++ хоть и похожи, но это инструменты для разных задач. Это как раньше писали код на С и делали ассемблерных вставки для ускорения задач. Так и сейчас в С++ вставки на С для ускорения кода и возможности работы напрямую с памятью без API прокладок. Я уже молчу что код на С без проблем переносится от версии к версии компилятора.
В своё время именно незабвенное творение Дохлогострауса и стандартной библиотеки С достало меня настолько, что я поменял карьеру и ушёл из разработки насовсем в QA автоматизацию на Python. Я пришёл к выводу, что за все годы кодинга на С/С++ я не написал ничего значительного, а какие то отдельные куски кода в каких то подсистемах, чаще всего которые даже протестировать то нормально было невозможно. Ну юнит тест, да: слёзы одни. Просто фрагментарные куски в огромной системе. Да, я фиговый разработчик и мне не особенно нравится писать код по требованиям, но даже с учётом этого С/С++ никогда не давал мне ощущения законченности и не приносил удовлетворения (не говоря о куче ошибок, которые находили потом QA). Да, на СС++ написаны драйвера и операционные системы и прочий рокет сайенс, но это просто не мой уровень.
Ну видимо тебе плевать, когда прога, которая должна жрать 300 КБ жрет 10 МБ и т.д.
Я вот от такого не имею никакой удовлетворенности...
Каждому овощу - свой фрукт :)
Я охотно использую python для быстрого прототипирования сервисов и систем, но когда речь заходит о продакшен-версиях, многое переписывается на плюсы именно из-за выигрыша в быстродействии и памяти. В итоге, получаем продукт, где верхнеуровневые грабли, в целом, пойманы и ликвидированы, а производительность в разы выше, чем в прототипе.
Что до С в С++, то "портабельный ассемблер" часто удобен, просто требует, как и любой инструмент, грамотного обращения. Например, аккуратных оберток для вызова из плюсов.
вредит чистоте и безопасности кода.
Как обычно, "старая песня" для криворуких, на какую я как-то ложил.
Продолжу использовать c в c++ и дальше, там где мне нравится.
Можете пожалуйста уточнить как использование низкоуровневых конструкций C в коде на C++ может влиять на безопасность и производительность программы?
Почему не стоит использовать C в C++