используя printf для печати плавающих значений

#include #include int main(void) { int x, *ptr_x; float f , *ptr_f; ptr_f = &f; ptr_x = &x; *ptr_x = 5; *ptr_f = 1.5; //printf("%d %f\n", f,x); printf ("\n\nxd = %d \t xf = %f \n ff = %f \t fd = %d", x,x,f,f); return 0; } 

Выход для ff =% f не ожидается.

xd = 5 xf = 0,000000
ff = 0,000000 fd = 1073217536

Точка этого кода должна показать, что произойдет, если плавающее значение будет напечатано с помощью% d, и если значение int будет напечатано% f.

Почему значение float не печатается правильно, даже если я использую% f?

printf () не является типичным.

Аргументы, которые вы передаете printf() , обрабатываются в соответствии с тем, что вы обещаете компилятору.

Кроме того, float s продвигается до double s, когда передается через переменные аргументы.

Поэтому, когда вы обещаете компилятору %f в первый раз (для xf ), компилятор забирает целую double (обычно 8 байт) из аргументов, проглатывая ваш float в этом процессе. Тогда второй %f разрезает прямо в нулевую мантису второго двойника.

Вот картина ваших аргументов:

 +-0-1-2-3-+-0-1-2-3-+-0-1-2-3-4-5-6-7-+-0-1-2-3-4-5-6-7-+ | x | x | f | f | +---------+---------+-----------------+-----------------+ %d--------|%f----------------|%f---------------|%d------| 

Но f выглядит так ( double ):

 f = 3FF8000000000000 

Давайте снова нарисуем его со значениями и размышляем о вашей конечности машины:

 | 05000000 | 05000000 | 00000000 0000F83F | 00000000 0000F83F | | %d, OK | %f, denormal... | %f, denormal... | %d, OK | 

Обратите внимание, что 1073217536 – 0x3FF80000.

После того, как вы передадите хотя бы один недопустимый спецификатор формата printf (например, попытайтесь напечатать значение float с %d или значение int с %f ), вся ваша программа будет запущена без ремонта. Последствия такого разрушительного действия можно увидеть где угодно в программе. В вашем случае попытка распечатать что-либо с недопустимым спецификатором формата привела к тому, что даже действительные спецификаторы формата перестали работать.

Говоря формально, вы написали программу, которая демонстрирует неопределенное поведение . Он может действовать совершенно непредсказуемо. Вы сами это сказали

Точка этого кода должна показать, что произойдет, если плавающее значение будет напечатано с помощью% d, и если значение int будет напечатано% f.

Поврежденное поведение, которое вы наблюдаете, демонстрирует именно это! Причудливо и непредсказуемо действующая программа – это именно то, что происходит, когда вы пытаетесь сделать что-то подобное.

Попробуй это:

 printf("size of int = %d, size of float = %d, size of double = %d\n", sizeof(int), sizeof(float), sizeof(double)); 

Когда вы вызываете printf() , система выставляет аргументы в стек. Таким образом, стек выглядит примерно так:

 pointer to format string [probably 4 bytes] x [probably 4 bytes] x [probably 4 bytes] f [probably 6 or 8 bytes] f [probably 6 or 8 bytes] 

Затем printf() выдает байты из стека, когда он анализирует строку формата. Когда он видит %d он выдает достаточно байтов для int, и когда он видит %f он выдает достаточно байтов для float. (На самом деле, поплавки повышаются до удвоения, когда они передаются в качестве аргументов функции, но важная идея состоит в том, что они требуют больше байтов, чем ints.) Поэтому, если вы «лжете» о аргументах, оно будет вызывать неправильное количество байтов и слепо преобразуйте их в соответствии с вашими инструкциями.

Таким образом, он сначала выдает правильное количество байтов для xd потому что вы правильно сказали ему, что x является int.

Но тогда он будет заполнять достаточно байтов для float, который будет потреблять второй x и часть первого f из стека и интерпретировать их как float для xf .

Затем он вытолкнет достаточно байтов для другого float, который будет потреблять оставшуюся часть первого f и часть второго f и интерпретировать их как float для ff .

Наконец, он вытолкнет достаточное количество байтов для int, которое будет потреблять оставшуюся часть второго f и интерпретировать их как int для fd .

Надеюсь, это поможет.

  • Что такое указатель void и что такое пустой указатель?
  • Как вернуть std :: string.c_str ()
  • Проходит ли указатель указателя, передается по значению в C ++?
  • Что такое «->» в Objective C?
  • указатель указателя в связанном списке добавить
  • Тестирование указателей на достоверность (C / C ++)
  • Приемник значений против приемника указателя в Голанге?
  • Как псевдоним имени функции в Fortran
  • Почему cout печатает массивы char по-разному от других массивов?
  • Скрытие нулевых значений, понимание того, почему голанг не удается здесь
  • Есть ли преимущества перехода по указателю на передачу по ссылке в C ++?
  • Давайте будем гением компьютера.