Проблема с умножением на дробь при замещении перед процессором (#define)

Я хотел бы начать с кода

#define myConst (419*0.9)
#define myConst1 (419*.9)
#define myConst9 (myConst1*.9)
#define myConst11 (419*1.1)

int main()
{
    printf("myConst:%d\n",myConst);
    printf("myConst1:%d\n",myConst1);
    printf("myConst9:%d\n",myConst9);
    printf("myConst11:%d\n",myConst11);
    return 0;
}

Что дало мне вывод как

MyConst: 1913895624
myConst1: 1
myConst9: 1
myConst11: 1

Я не знаю, почему умножение на дробь в #define приводит к значению, отличному от ожидаемого? А также значение myConst непрерывно меняется, например, некоторые значения, которые я наблюдал, составляют -254802840 -1713343480 466029496. А также myConst1,myConst9 и myConst11 дают мне 1, что, по моему мнению, не логично.

Любое объяснение относительно того же самого приветствуется.

1 ответ

Решение

#define не играет никакой роли в этом; проблема в том, что вы передаете double когда printf ожидает int (из-за %d Спецификатор); технически это неопределенное поведение, так что все может произойти.

Теперь, если бы он был построен на 32-битной x86, вероятно, вы бы получили int реинтерпретация младших 32 битов с плавающей запятой, поскольку все параметры обычно передаются в стеке. Но я думаю, что это работает на 64-битной x86, где параметры передаются в разные регистры, если они с плавающей запятой. В этом случае, printf просто читает какой-то мусор, который находится в каком-то регистре в это время, в этих значениях не так много логики.

Обратите внимание, что почти любой компилятор может предупредить вас о таком несоответствии между строкой формата и фактически переданными значениями. Для gcc и clang я предлагаю вам включить это предупреждение (-Wformat, включен в -Wall, что вы должны обязательно включить), и, возможно, пометить его как фактическую ошибку (-Werror=format), так как нет законных оснований нарушать printf как это.

Другие вопросы по тегам