【发布时间】:2018-12-18 20:05:37
【问题描述】:
我制作了这个程序来测试任意整数文字被评估为哪些数据类型。这个程序的灵感来自于阅读 StackOverflow 上的其他一些问题。
How do I define a constant equal to -2147483648?
Why do we define INT_MIN as -INT_MAX - 1?
(-2147483648> 0) returns true in C++?
在这些问题中,我们有一个问题:程序员想把INT_MIN写成-2^31,但是2^31实际上是一个字面量和@ 987654326@ 是一元否定运算符。由于 INT_MAX 通常是 2^31 - 1 具有 32 位 int,因此文字 2^31 不能表示为 int,因此它被提升为更大的数据类型。第三个问题的第二个答案有一个图表,根据该图表确定整数文字的数据类型。编译器从顶部向下遍历列表,直到找到适合文字的数据类型。
Suffix Decimal constants none int long int long long int
================================================ ============================
在我的小程序中,我定义了一个宏,它将以 C 字符串的形式返回变量、文字或表达式的“名称”。基本上,它返回在宏内部传递的文本,与您在代码编辑器中看到的完全一样。我用它来打印文字表达式。
我想确定表达式的数据类型,它的计算结果。我必须对我如何做到这一点有点聪明。我们如何确定 C 中变量或表达式的数据类型?我得出的结论是,只需要两个“位”信息:数据类型的宽度(以字节为单位)和数据类型的符号。
我使用sizeof() 运算符来确定数据类型的宽度(以字节为单位)。我还使用另一个宏来确定数据类型是否已签名。 typeof() 是一个 GNU 编译器扩展,它返回变量或表达式的数据类型。但我无法读取数据类型。我将-1 类型转换为该数据类型。如果它是有符号数据类型,它仍然是-1,如果它是一个无符号数据类型,它将成为该数据类型的UINT_MAX。
#include <stdio.h> /* C standard input/output - for printf() */
#include <stdlib.h> /* C standard library - for EXIT_SUCCESS */
/**
* Returns the name of the variable or expression passed in as a string.
*/
#define NAME(x) #x
/**
* Returns 1 if the passed in expression is a signed type.
* -1 is cast to the type of the expression.
* If it is signed, -1 < 0 == 1 (TRUE)
* If it is unsigned, UMax < 0 == 0 (FALSE)
*/
#define IS_SIGNED_TYPE(x) ((typeof(x))-1 < 0)
int main(void)
{
/* What data type is the literal -9223372036854775808? */
printf("The literal is %s\n", NAME(-9223372036854775808));
printf("The literal takes up %u bytes\n", sizeof(-9223372036854775808));
if (IS_SIGNED_TYPE(-9223372036854775808))
printf("The literal is of a signed type.\n");
else
printf("The literal is of an unsigned type.\n");
return EXIT_SUCCESS;
}
如您所见,我正在测试 -2^63 以查看它是什么数据类型。问题在于,在 ISO C90 中,整数文字的“最大”数据类型似乎是 long long int,如果我们可以相信图表的话。众所周知,long long int 在现代 64 位系统上的数值范围为 -2^63 到 2^63 - 1。但是,上面的 - 是一元否定运算符,实际上并不是整数文字的一部分。我正在尝试确定 2^63 的数据类型,这对于long long int 来说太大了。我试图在 C 的类型系统中引起错误。这是故意的,仅用于教育目的。
我正在编译和运行程序。我使用-std=gnu99 而不是-std=c99,因为我使用的是typeof(),这是一个GNU 编译器扩展,实际上并不是ISO C99 标准的一部分。我得到以下输出:
$ gcc -m64 -std=gnu99 -pedantic experiment.c
$
$ ./a.out
The literal is -9223372036854775808
The literal takes up 16 bytes
The literal is of a signed type.
我看到等价于 2^63 的整数文字计算为 16 字节有符号整数类型!据我所知,C 编程语言中没有这种数据类型。我也不知道有任何英特尔 x86_64 处理器有一个 16 字节的寄存器来存储这样的右值。如果我错了,请纠正我。解释这里发生了什么?为什么没有溢出?另外,是否可以在 C 中定义 16 字节的数据类型?你会怎么做?
【问题讨论】:
-
宽度和符号不足以识别类型,即使是整数类型。例如,
long的大小几乎总是与int或long long相同。 -
好吧,显然
long和long long都不是16 字节!为了识别整数数据类型,您有什么建议? -
我相信某些版本的 gcc 实现了 128 位类型,尽管它通常是“在软件中模拟的”,因为您是对的,大多数 CPU 没有寄存器,而 ALU 的操作在这样的大小上.
-
如果您想根据表达式的类型做出决定,
_Generic将是标准方法。 -
打印
sizeof的结果,你应该使用%zu