Комментарии 18
Спасибо за перевод! Эту серию статей давно надо было перевести.
Я думаю, вы можете даже им отправить перевод для публикации на сайте: у них уже есть перевод на японский.
Не знал, что преобразование int* во float* неопределено. А float* в int*? А double* в int* и обратно?
Ни одно из них не определено, об этом недавно писали на хабре и вот есть ссылка на эту тему: youtu.be/ACW-7dktyDk
Правильно делать через memcpy, оптимизирующий компилятор сам удалит ненужный вызов функции.
Правильно делать через memcpy, оптимизирующий компилятор сам удалит ненужный вызов функции.
Не знал, что преобразование int* во float* неопределено.Отлично оно определено, не надо наездов! Другое дело, что перед использованием нужно обратно из float* в Int* преобразовать.
Ну и зачем тогда оно такое нужно? Проще считать что оно не определено само по себе, меньше wtfpm в коде будет.
Ну и зачем тогда оно такое нужно?А зачем, скажем,
void*
нужен? Для тех же целей можно и int*
использовать. Например если у вас функция принимает int*
и потом передаёт его в callback
— то можно передать указатель на float*
, сконвертировав его в нужный тип — а потом сконвертировать обратно.На каламбуре типизации свет клином не сошёлся, в языке много других фич есть…
Не все-таки не пойму при чем здесь memcpy?
int a=1;
int* pa = &a;
float* pfa = (float*)pa;
Тут ни одного копирования нет. Куда тут memcpy сунуть? Наверное, в статье имелось ввиду что-то другое.
int a=1;
int* pa = &a;
float* pfa = (float*)pa;
Тут ни одного копирования нет. Куда тут memcpy сунуть? Наверное, в статье имелось ввиду что-то другое.
Думаю, подразумевалось следующее:
int a = 1;
float b;
int *pa = &a;
float *pb = &b;
memcpy(pb, pa, sizeof(a));
Результат этой операции: (float*)pa; не определён в соответствии со стандартом.
Правильно так, например:
Правильно так, например:
int i = 1;
float res;
memcpy(&res, &i, sizeof i);
Результат этой операции: (float*)pa; не определён в соответствии со стандартом.На самом деле определён. Не определено разименование этого указателя.
Записали
int
читайте int
. Записали float
— читайте тоже float
.Тест для само-проверки: представьте, что работа с
float
ами выполняется отдельным [со]процессором (а когда-то так и было — что 68881, что 8087 — это отдельные железки) и он работает параллельно с основным процессором. Соответственно если мы не вставим явную инструкцию синхронизации никто вам не гарантирует, что данные, которые вы хотите прочитать уже будут готовы к тому моменту, когда вы соберёсь их читать.Таким образом описанный в известной статье код работает только на достаточно узком наборе железа и сопутствующих компилфторов: в 1980е — железо не позволяло ему правильно работать, а уже в нашем веке — компиляторы.
Но вот там и тогда, когда оно использовалось — да, оно работало…
В соответствии со стандартом результат этой операции не определён, если он имеет некорректное выравнивание. Если же мы каким-либо образом удостоверились, что выравнивание корректно, то компилятор обязан обеспечить ожидаемое поведение
Как я уже сказал преобразование указателей — это ерунда. Вот использование указателей — это уже неопределённое поведение. На stack overflow есть подробное обсуждение. С неформальным обсуждением и ссылками на пункты стандарта.
Маленькая поправка:
В оригинале написано
Для беззнаковых переменных ничего не стоит гарантировать переполнение по модулю 2 (заворачивание)
В оригинале написано
It is worth noting that unsigned overflow is guaranteed ...— «стоит отметить, что беззнаковое переполнение гарантировано...»
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Что каждый программист на C должен знать об Undefined Behavior. Часть 1/3