Как разница в спецификаторах формата влияет на значение?

#c

#c

Вопрос:

 #define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main(void)
{
    int a = 5;
    float b = 10;
    double c = 15;
    printf("%d %f %lfn", a, a, a);
    printf("%d %f %lfn", b, b, b);
    printf("%fn", b);
    printf("%d %f %lfn", c, c, c);
    printf("%lfn", c);
}
  

Вывод:

 5 0.000000 0.000000
0 0.000000 0.000000
10.000000
0 0.000000 0.000000
15.000000 
  

Я не понимаю, почему в первом случае выводится 0 для b и c, даже для соответствующего спецификатора формата?

Я использую Visual Studio.

Ответ №1:

Вы должны знать, что компилятор C недостаточно умен, чтобы понимать строку формата и правильно приводить следующие аргументы. Поэтому ваши аргументы, вероятно, будут обработаны неправильно; для printf это всего лишь несколько байтов в стеке. Представление a double со значением 15.0, скорее всего, содержит несколько байтов 0 в стеке, которые printf читаются как int s, потому что вы сказали ему сделать это в строке формата.

Ответ №2:

Использование неправильной спецификации преобразования вызывает неопределенное поведение. Вы можете получить ожидаемый или неожиданный результат или даже сбой программы.

C11: 7.21.6 Форматированные функции ввода / вывода:

Если спецификация преобразования недействительна, поведение не определено.

Комментарии:

1. Верно, но довольно бессмысленно для того, кто пытается понять, что происходит.

2. Более того, можно даже получить 42!

3. @luk32; Или даже сбой жесткого диска!

4. @haccks Я подумал, что компилятор, который намеренно выводит 42 в UB, был бы забавной вещью. Но ваша идея полностью затмевает это =).

5. @luk32; Мне нравится портить ВЕСЕЛЬЕ! 😛

Ответ №3:

Да, вы используете правильный спецификатор формата в части строки формата, но поскольку вы уже ранее использовали неправильный спецификатор формата в строке формата, вы уже вызвали весь ад, чтобы вырваться на свободу.

В частности, printf к моменту замены бит %f и %lf уже «не соответствует» вашим аргументам данных.