Неожиданные типы из UINT32 C, UINTN C

7.20.4.1 макросы для целочисленных констант минимальной ширины
... Макрос UINTN_C(value) расширяется до целочисленного постоянного выражения, соответствующего типу uint_leastN_t. Например, если uint_least64_t - это имя типа unsigned long long int, потом UINT64_C(0x123) может расширяться до целочисленной константы 0x123ULL. C11dr §7.20.4.1 1

типа UINTN_C() и друзья не так, как ожидалось. См." ожидаемые " комментарии в выводе кода.

A) Является ли моя реализация компилятора неправильной, и тип константы должен быть uint_leastN_t?
или
B) должен ли тип константы от UINTN_C(value) быть минимум uint_leastN_t, int, unsigned и тип, необходимый для кодирования значения?
или
В) что-то еще?


я ожидал, что тип констант будет соответствовать uint_leastN_t, но, похоже, это не так при 2 условиях:

* * 1, если соответствующий тип макроса ниже int/unsigned, в константа int/unsigned

**2 Если значение превышает диапазон uint_leastN_t, тогда тип становится более широкой константой типа.

§6.4.4.1 " тип целочисленной константы является первым из соответствующего списка, в котором может быть представлено ее значение ... (далее следует длинный список).


#include <limits.h>
#include <stdio.h>

#define type_of(X) _Generic((X), 
  unsigned long long: "unsigned long long", 
  unsigned long: "unsigned long", 
  unsigned: "unsigned", 
  int: "int", 
  unsigned short: "unsigned short", 
  default: "?" 
  )

int main() {
  uint_least16_t u16 = 0;
  uint_least32_t u32 = 0;
  uint_least64_t u64 = 0;
  printf("%zu %sn", sizeof(u16), type_of(u16));
  printf("%zu %sn", sizeof(u32), type_of(u32));
  printf("%zu %sn", sizeof(u64), type_of(u64));
  puts("");
  printf("%zu %sn", sizeof((uint_least16_t) UINT16_C(0)), type_of((uint_least16_t) UINT16_C(0)));
  printf("%zu %sn", sizeof UINT16_C(0), type_of(UINT16_C(0)));
  printf("%zu %sn", sizeof UINT16_C(0x1234), type_of(UINT16_C(0x1234)));
  printf("%zu %sn", sizeof UINT16_C(0x12345), type_of(UINT16_C(0x12345)));
  printf("%zu %sn", sizeof UINT32_C(0x12345678), type_of(UINT32_C(0x12345678)));
  printf("%zu %sn", sizeof UINT32_C(0x123456789), type_of(UINT32_C(0x123456789)));
  return 0;

  //round_frac_test(-2.05446162500000000e+06, 205);
  round_frac_test(fp_rand(), 6);
  round_frac_tests(10000);
  puts("Done");
  return 0;
}

выход

2 unsigned short
4 unsigned
8 unsigned long long

2 unsigned short
4 int       // Expected 2 unsigned short, see **1
4 int       // Expected 2 unsigned short, see **1
4 int       // Expected 2 unsigned short, see **2
4 unsigned
8 unsigned long long  // Expected 4 unsigned, see **2

я использую (GNU C11 (GCC) версия 5.4.0)

при формировании этого поста я склоняюсь по направлению к Б, и все же я ищу ваше рациональное подтверждение-один путь другого. Если B так, разочаровывающая часть-это UINTN_C() может привести к подпись тип.

я полагаю, что это то, о чем идет речь в части" минимальная ширина".

2 ответов


это описано в Родительском подразделе 7.20.4.

в той части, которую вы процитировали:

макрос UINTN_C(value) расширяется до целочисленного постоянного выражения >, соответствующего типу uint_leastN_t.

Он говорит:"соответствующую", не то, что расширение на самом деле of этого типа. Смысл "соответствующую" объясняется в 7.20.4p3:

каждый вызов один из этих макросов должен расширяться до целого числа постоянное выражение, подходящее для использования в #if директивы препроцессора. Тип выражения должен иметь тот же тип, что и выражение соответствующего типа, преобразованное в соответствии с целочисленные акции. Значение выражения должно быть аргумент.

поскольку макросы предназначены для использования в элементе


на хосте с 16 бит short и 32-разрядные целые числа unsigned short цифры повышаются до int. Таким образом, эти макросы определяются как:

#define INT16_C(x) (x)
#define UINT16_C(x) (x)

без суффикса " U " для unsigned short

если int может представить все значения исходного типа (Как ограничено по ширине, для битового поля), значение преобразуется в int;

эти макросы расширяются только до соответствующих констант (или целочисленных литералов, использующих более распространенные язык), и не создавайте никаких объектов, и должны использоваться в #if. Так что никаких гипсов не допускается. Макросы также не выполняют никаких проверок диапазона.

int16_t x0 = 123;
uint16_t x1 = 123;    // no sign suffix needed
int32_t x2 = 2147483647;
uint32_t x3 = 2147583647U;  //sign suffix theoreticaly needed as int and unsigned int have the same rank
int64_t x4 = 9223372036854775807LL; 
uint64_t x5 = 9237372036854775807ULL; //same as above