С растом все ок, а вот в сишном коде UB.
Память с точки зрения компьютера или ОС нетипизирована, но ты не на ассемблере пишешь и не системные вызовы делаешь.
Ну а в С такая модель памяти, какая есть, ее надо соблюдать. cc @zamazan4ik
В C фактически сделано так же как я в итоге сделал на Rust с конвертированием в слайс (это я изначально не правильно решил конвертить Vec<f64> в Vec<i32> т.к. не подумал про layout). В C разве что нет гарантий того, что нельзя будет после конвертации использовать исходный указатель на f64 и эта ответственность перекладывается на разработчика.
В расте, скорее всего, можно сделать корректно, а вот в си тот же трюк сделать без memcpy и без UB не выглядит возможным. Неинициализированная память здесь ни при чем, а вот про strict aliasing верно отметили выше. Вообще это плюс расту, где модель памяти оказывается гибче сишной.
Что-то я так и не улавливаю о какой проблеме в C все говорят. Вроде бы всё просто - выделили память под sizeof(double) * N , но вместо этого стали её использовать для sizeof(INT32) * N В чём тут проблема?
В том, что ты обратился по указателю типа int* к объекту типа float. Это UB.
Почитай про алиасинг.
Так я не обратился к нему - я сначала записал в него INT32, и только потом обратился
И запись и чтение в данном случае одинаково запрешены
А чё запись запрещена?
Нет. Запись возможна, если эта память выделена с помощью malloc и подобных
В C она так и выделяется - через malloc
using an lvalue expression (typically, dereferencing a pointer) of a different type T2 is undefined behavior, unless
Если записал int32_t туда, где раньше лежала половина double (в динамически аллоцированную память) и потом читаешь, то это корректно с точки зрения си. Только по эффективности это будет почти как memcpy
По сравнению с тем, что бы аллоцировать такой же буфер чисто под int32 выходит эффективнее. Ещё и фрагментацию памяти немного снижает.
Тогда консенсус достигнут, и можно завершать оффтоп с итоговым результатом +1 к расту.)
Обсуждают сегодня