Программа на C: справка о последовательности определения переменных - PullRequest
1 голос
/ 28 января 2012
void main()
{
    float x = 8.2;
    int r = 6;
    printf ( "%f" ,  r/4);
}

Совершенно странно, что я не являюсь явно типизующим типом r (типа int) в функции printf для float.Однако, если я изменяю последовательность объявления x и r и сначала объявляю r, а затем xi получаю разные результаты (в этом случае это значение мусора).Опять же, я нигде не использую x в программе. Это то, что я хотел ошибиться ... Я хочу, чтобы они оставались такими, какие они есть.Но когда я извиняюсь за первый кусок кода, я получаю 157286.375011 как результат (мусорное значение).

void main()
{
    int r = 6;
    float x = 8.2;
    printf ( "%f" ,  r/4);
}

, и если я выполняю код выше, я получаю 0.000000 как результат.я знаю, что результаты могут пойти не так, потому что я использую% f в printf, когда это должно было быть% d ... результаты могут быть неправильными ... но мой вопрос заключается в том, почему результаты меняются, когда я меняю последовательность определений переменных.Разве это не должно быть одинаково, правильно или неправильно ???

Почему это происходит?

Ответы [ 3 ]

8 голосов
/ 28 января 2012

printf не имеет проверки типов. Он полагается на то, что вы проверяете себя, проверяете ли все типы на соответствие спецификаторам форматирования.

Если вы не делаете это, вы входите в область неопределенного поведения, где может произойти все что угодно. Функция printf пытается интерпретировать указанное значение с точки зрения используемого вами спецификатора формата. И если они не совпадают, бум.

Бессмысленно указывать %f для int, но вы уже знали, что ...

3 голосов
/ 28 января 2012

f спецификатор преобразования принимает аргумент double, но вы передаете аргумент int.Передача аргумента int в f в спецификатор преобразования является неопределенным поведением.

В этом выражении:

r / 4

оба операнда имеют тип int, а результат также имеет типint.

Вот что вы хотите:

printf ("%f",  r / 4.0);
1 голос
/ 28 января 2012

Когда printf захватывает необязательные переменные (т. Е. Переменные после char *, указывающие, что печатать), он должен убрать их из стека.double обычно составляет 64 бита (8 байтов), тогда как int составляет 32 бита (4 байта).

Более того, числа с плавающей запятой имеют нечетную внутреннюю структуру по сравнению с целыми числами.

Поскольку вы передаете int вместо double, printf пытается получить 8 байтов из стека вместо четырех, и он пытается интерпретировать байты int как байтыdouble.

Так что вы не только получаете 4 байта памяти, содержащей , никто не знает, что , но вы также интерпретируете эту память - это 4 байта int и4 байта случайного материала из ниоткуда - как если бы это был double.

Так что да, странные вещи произойдут.Когда вы перекомпилируете (или даже время перезапускаете ) программу, которая просто произвольно выбирает вещи из памяти, где у нее нет malloc 'd и она не сохранена, вы собираетесьчтобы получить непредсказуемые и дико изменяющиеся значения.

Не делайте этого.

...