2017-01-03 4 views
-1
#include <stdio.h> 

int main(void) { 
    printf("%d\n", 50.2); 
    return 0; 
} 

~ Когда я его выполню.C программирование printf ("% d", 50,2);

enter image description here

Двоичный 50,2 представляет собой (0100 0010 0100 1000 1100 1100 1100 1101).

Итак, я ожидал 1,112,067,277, но значения не были и не фиксированы.

Значения меняются каждый раз, почему?

+0

Проверьте свой код –

+0

Вам необходимо скомпилировать с помощью 'gcc -Wall -g yoursource.c -o yourprog' (все предупреждения и информацию об отладке), улучшить код, чтобы не получать никаких предупреждений, а затем запускать'./Yourprog' и отлаживать это с 'gdb./yourprog' –

+4

Пожалуйста, не публикуйте скриншоты для вывода обычного текста. Просто скопируйте и вставьте текст в свой вопрос. – Gerhardh

ответ

6

Проблема заключается в том, что вы используете неверный спецификатор формата в printf, %d вместо %f. Это вызывает неопределенное поведение.

Всякий раз, когда вы вызываете неопределенное поведение, не может быть никаких детерминированных или ожидаемых результатов. Когда у вас есть неопределенное поведение, компилятор может идти вперед и делать странные предположения, такие как «этот плавающий литерал никогда не используется, поэтому нет необходимости выделять для него память». Это означает, что вы можете распечатать места памяти мусора или даже сбой вашей программы. Поэтому анализ того, почему неопределенное поведение дал определенный результат, не является значимой задачей.

Чтобы гарантировать детерминированное поведение, вы должны сделать что-то вроде этого:

#include <stdio.h> 
#include <stdint.h> 
#include <inttypes.h> 
#include <string.h> 

int main(void) 
{ 
    const double number = 50.2; 
    union 
    { 
    double d; 
    uint8_t u8 [sizeof(double)]; 
    } u = { number }; 

    printf("Binary representation of %f:\n", number); 
    for(size_t i=0; i<sizeof(double); i++) 
    { 
    printf("%.2" PRIx8 " ", u.u8[i]); 
    } 
    printf("\n\n"); 
    printf("Integer (nonsense) representation of %f:\n", number); 
    int i; 
    memcpy(&i, u.u8, sizeof(int)); 
    printf("%d", i); 

    return 0; 
} 

Выход:

Binary representation of 50.200000: 
9a 99 99 99 99 19 49 40 

Integer (nonsense) representation of 50.200000: 
-1717986918 

Это было на машине, где дважды был 8 байт и целых 4 байта/маленький endian, что означает, что вы получите 4 наименее значимых байта в качестве некоторого бессмысленного вывода (а именно, числа 9999999Ah).

+1

Не пишет одному члену союза, а затем читает от другого, UB? –

+1

@RudyVelthuis Это всегда UB в C++, но не обязательно в C. C позволяет использовать его согласно C11 6.5.2.3/3. См. Примечание к ноте 95: «Если элемент, используемый для чтения содержимого объекта объединения, не совпадает с элементом, который последний использовал для , сохраните значение в объекте, соответствующая часть представления объекта значения будет переинтерпретирована as представление объекта в новом типе, как описано в 6.2.6 (процесс, иногда называемый «type punning»). Это может быть ловушечное представление. ». Это может быть или не быть UB в C, в зависимости от того, поддерживает ли система ловушки или нет. – Lundin

+1

Однако тип символа (среди которых мы можем с уверенностью считать 'uint8_t', учитывая, что компилятор является нормальным) никогда не может иметь ловушку. Поэтому всегда безопасно разделить любой тип данных на C на байты, но не обязательно наоборот. – Lundin

8

Это связано с тем, что использование неправильного типа аргумента для спецификатора формата вызывает undefined behavior.

Цитирование C11, глава §7.21.6.1, fprintf()

d, i         int аргумент преобразуется в десятичное

, который говорит, что %d ожидает аргумент типа int и,

[....] Если какой-либо аргумент Неправильный тип для соответствующей спецификации преобразования, поведение не определено.

Итак, вы передаете double (в целом, даже float аргумент также получает звание double.), где int ожидается.

+0

@StoryTeller. Правильно, это буква «double», просто хотелось предположить, что в случае наличия переменной float она будет повышена. –

7

Причина, по-видимому, случайных значений заключается в том, что на вашей платформе printf() ожидает целочисленные аргументы в других регистрах, которые содержат float/double аргументы. На x86_64, например % еси (интермедиат) против % XMM0 (поплавок)

Согласно C Standard это нормально, так как вы вызываете неопределенное поведение из-за неправильного спецификатором преобразования.

+0

FWIW, ваш «% esi vs.% xmm0» предназначен для Linux x86_64. В Windows x86_64 это RCX против XMM0. Такая же проблема, другой регистр. –