2014-11-05 5 views
1

В стандарте C99 различаются неявные и явные преобразования типов (6.3 Конверсии). Я думаю, но не мог найти, что неявные отведения выполняются, когда целевой тип имеет большую точность, чем источник, и может представлять его значение. [Это то, что я считаю, происходит от INT до DOUBLE]. Учитывая, что я смотрю на следующем примере:Понимание неявных преобразований для printf

#include <stdio.h> // printf 
#include <limits.h> // for INT_MIN 
#include <stdint.h> // for endianess 
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 

int main() 
{ 
    printf("sizeof(int): %lu\n", sizeof(int)); 
    printf("sizeof(float): %lu\n", sizeof(float)); 
    printf("sizeof(double): %lu\n", sizeof(double)); 
    printf(IS_BIG_ENDIAN == 1 ? "Big" : "Little"); printf(" Endian\n"); 

    int a = INT_MIN; 
    printf("INT_MIN: %i\n", a); 
    printf("INT_MIN as double (or float?): %e\n", a); 
} 

Я был очень удивлен, обнаружив, что выход:

sizeof(int): 4 
sizeof(float): 4 
sizeof(double): 8 
Little Endian 
INT_MIN: -2147483648 
INT_MIN as double (or float?): 6.916919e-323 

Таким образом, значение с плавающей точкой Печатаемая субнормальным число с плавающей точкой вблизи минимальна субнормальны положительный двойной 4.9406564584124654 × 10^-324. Странные вещи происходят, когда я закомментировать две Printf для порядок байтов, я получаю другое значение для двойной:

#include <stdio.h> // printf 
#include <limits.h> // for INT_MIN 
#include <stdint.h> // for endianess 
#define IS_BIG_ENDIAN (*(uint16_t *)"\0\xff" < 0x100) 

int main() 
{ 
    printf("sizeof(int): %lu\n", sizeof(int)); 
    printf("sizeof(float): %lu\n", sizeof(float)); 
    printf("sizeof(double): %lu\n", sizeof(double)); 
    // printf(IS_BIG_ENDIAN == 1 ? "Big" : "Little"); printf(" Endian\n"); 

    int a = INT_MIN; 
    printf("INT_MIN: %i\n", a); 
    printf("INT_MIN as double (or float?): %e\n", a); 
} 

выход:

sizeof(int): 4 
sizeof(float): 4 
sizeof(double): 8 
INT_MIN: -2147483648 
INT_MIN as double (or float?): 4.940656e-324 
  • НКУ --version: (Ubuntu 4.8.2- 19ubuntu1) 4.8.2
  • uname: x86_64 GNU/Linux
  • опции компилятора, где: GCC -ox хс -Wall -Wextra -std = c99 --pedantic
  • И да там, где одно предупреждение:
x.c: In function ‘main’: 
x.c:15:3: warning: format ‘%e’ expects argument of type ‘double’, but argument 2 
      has type ‘int’ [-Wformat=] 

    printf("INT_MIN as double (or float?): %e\n", a); 
^

Но я до сих пор не могу понять, что именно происходит.

  • в небольшом порядке байт Я считаю MIN_INT как: 00 ... 0001 и MIN_DBL (Субнормальный) в 100..00 #, начиная с мантиссой, а затем экспонентом и заключить с # как знаковым битом.
  • Является ли эта форма применения спецификатора формата «% e» для int, является неявным литом ?, реинтерпрет?

Я потерян, пожалуйста, просветите меня.

+2

Существует различие между 'cast'-ing и поставкой несовместимого' спецификатора формата '' для 'printf()'. Позднее действие приводит к UB. –

+0

Я предлагаю вам изменить свой код, чтобы иметь один правильный printf и один неверный printf, затем скомпилировать его на сборку и посмотреть на разницу между ними. Вы узнаете, как двойной должен быть передан в функции varargs, и как он пытался передать ваш int как double. – JS1

ответ

2
printf("INT_MIN as double (or float?): %e\n", a); 

Выше линии имеет проблемы Вы не можете использовать %e для печати Интс. Поведение не определено.

Вы должны использовать

printf("INT_MIN as double (or float?): %e\n", (double)a); 

или

double t = a; 
printf("INT_MIN as double (or float?): %e\n", t); 

Related post: Это сообщение объясняет, как с помощью некорректных спецификаторов печати в Printf может привести к UB.

+0

Связанный пост был очень полезен. – math

+0

@math Я рад, что это помогло. –

0

Аргументы для va_arg функции не преобразуются, синтаксически компилятор ничего не знает об аргументах для таких функций, поэтому он не может этого сделать. Однако современные компиляторы знают, как интерпретировать строку формата, и поэтому они могут предупредить вас, когда происходит что-то подозрительное. Это то, что происходит, когда вы видите предупреждение от gcc.

Чтобы быть более точным, есть некоторые акции, которые сделаны для узких целочисленных типов, они продвигаются к int, и float, который назначен double. Но это все волшебство, которое может произойти здесь.

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

BTW, для size_t с вашего sizeof выражений правильный %zu.

Смежные вопросы