[英]What is a 16 byte signed integer data type?"
I made this program to test what data types arbitrary integer literals get evaluated to. 我制作了这个程序来测试任意整数文字被评估的数据类型。 This program was inspired from reading some other questions on StackOverflow.
这个程序的灵感来自阅读StackOverflow上的其他一些问题。
How do I define a constant equal to -2147483648? 如何定义一个等于-2147483648的常量?
Why do we define INT_MIN as -INT_MAX - 1? 为什么我们将INT_MIN定义为-INT_MAX - 1?
(-2147483648> 0) returns true in C++? (-2147483648> 0)在C ++中返回true?
In these questions, we have an issue: the programmer wants to write INT_MIN as -
2^31 , but 2^31 is actually a literal and -
is the unary negation operator. 在这些问题中,我们遇到了一个问题:程序员想要将INT_MIN写为
-
2 ^ 31 ,但是2 ^ 31实际上是一个文字而且-
是一元否定运算符。 Since INT_MAX is usually 2^31 - 1 having a 32-bit int, the literal 2^31 cannot be represented as an int
, and so it gets promoted to a larger data type. 由于INT_MAX通常为2 ^ 31 - 1,具有32位int,因此文字2 ^ 31不能表示为
int
,因此它将被提升为更大的数据类型。 The second answer in the third question has a chart according to which the data type of the integer literals is determined. 第三个问题的第二个答案有一个图表,根据该图表确定整数文字的数据类型。 The compiler goes down the list from the top until it finds a data type which can fit the literal.
编译器从顶部向下列表,直到找到适合文字的数据类型。
Suffix Decimal constants none int long int long long int
========================================================================= ================================================== =======================
In my little program, I define a macro that will return the "name" of a variable, literal, or expression, as a C-string. 在我的小程序中,我定义了一个宏,它将变量,文字或表达式的“名称”作为C字符串返回。 Basically, it returns the text that is passed inside of the macro, exactly as you see it in the code editor.
基本上,它返回在宏内部传递的文本,就像在代码编辑器中看到的那样。 I use this for printing the literal expression.
我用它来打印文字表达式。
I want to determine the data type of the expression, what it evaluates to. 我想确定表达式的数据类型,它的评估结果。 I have to be a little clever about how I do this.
我必须对我如何做到这一点有点聪明。 How can we determine the data type of a variable or an expression in C?
我们如何确定C中变量或表达式的数据类型? I've concluded that only two "bits" of information are necessary: the width of the data type in bytes, and the signedness of the data type.
我得出结论,只需要两个“位”信息:数据类型的宽度(以字节为单位),以及数据类型的符号。
I use the sizeof()
operator to determine the width of the data type in bytes. 我使用
sizeof()
运算符来确定数据类型的宽度(以字节为单位)。 I also use another macro to determine if the data type is signed or not. 我还使用另一个宏来确定数据类型是否已签名。
typeof()
is a GNU compiler extension that returns the data type of a variable or expression. typeof()
是一个GNU编译器扩展,它返回变量或表达式的数据类型 。 But I cannot read the data type. 但我无法读取数据类型。 I typecast
-1
to whatever that data type is. 我对这种数据类型进行了类型转换
-1
。 If it's a signed data type, it will still be -1
, if it's an unsigned data type, it will become the UINT_MAX
for that data type. 如果它是有符号数据类型,它仍然是
-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;
}
As you can see, I'm testing -
2^63 to see what data type it is. 如您所见,我正在测试
-
2 ^ 63以查看它是什么数据类型。 The problem is that in ISO C90, the "largest" data type for integer literals appears to be long long int
, if we can believe the chart. 问题是在ISO C90中,如果我们可以相信图表,那么整数文字的“最大”数据类型似乎是
long long int
。 As we all know, long long int
has a numerical range -2^63 to 2^63 - 1 on a modern 64-bit system. 众所周知,
long long int
在现代64位系统上的数值范围为-2 ^ 63到2 ^ 63 - 1 。 However, the -
above is the unary negation operator, not really part of the integer literal. 但是,
-
上面是一元否定运算符,而不是整数字面的一部分。 I'm attempting to determine the data type of 2^63 , which is too big for the long long int
. 我正在尝试确定2 ^ 63的数据类型,这对于
long long int
来说太大了。 I'm attempting to cause a bug in C's type system. 我试图在C的类型系统中造成错误。 That is intentional, and only for educational purposes.
这是故意的,仅用于教育目的。
I am compiling and running the program. 我正在编译并运行该程序。 I use
-std=gnu99
instead of -std=c99
because I am using typeof()
, a GNU compiler extension, not actually part of the ISO C99 standard. 我使用
-std=gnu99
而不是-std=c99
因为我使用的是typeof()
,一个GNU编译器扩展,实际上并不是ISO C99标准的一部分。 I get the following output: 我得到以下输出:
$ 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.
I see that the integer literal equivalent to 2^63 evaluates to a 16 byte signed integer type! 我看到等价于2 ^ 63的整数文字计算为16字节有符号整数类型! As far as I know, there is no such data type in the C programming language.
据我所知,C编程语言中没有这样的数据类型。 I also don't know of any Intel x86_64 processor that has a 16 byte register to store such an rvalue.
我也不知道任何具有16字节寄存器的Intel x86_64处理器来存储这样的rvalue。 Please correct me if I'm wrong.
如果我错了,请纠正我。 Explain what's going on here?
解释这里发生了什么? Why is there no overflow?
为什么没有溢出? Also, is it possible to define a 16 byte data type in C?
此外,是否可以在C中定义一个16字节的数据类型? How would you do it?
你会怎么做?
After some digging this is what I've found. 经过一番挖掘,这就是我发现的。 I converted the code to C++, assuming that C and C++ behave similarly in this case.
我将代码转换为C ++,假设在这种情况下C和C ++的行为相似。 I want to create a template function to be able to accept any data type.
我想创建一个模板函数,以便能够接受任何数据类型。 I use
__PRETTY_FUNCTION__
which is a GNU compiler extension which returns a C-string containing the "prototype" of the function, I mean the return type, the name, and the formal parameters that are input. 我使用
__PRETTY_FUNCTION__
这是一个GNU编译器扩展,它返回一个包含函数“原型”的C字符串,我的意思是返回类型,名称和输入的形式参数。 I am interested in the formal parameters. 我对形式参数感兴趣。 Using this technique, I am able to determine the data type of the expression that gets passed in exactly, without guessing!
使用这种技术,我能够确定完全传递的表达式的数据类型,而无需猜测!
/**
* This is a templated function.
* It accepts a value "object" of any data type, which is labeled as "T".
*
* The __PRETTY_FUNCTION__ is a GNU compiler extension which is actually
* a C-string that evaluates to the "pretty" name of a function,
* means including the function's return type and the types of its
* formal parameters.
*
* I'm using __PRETTY_FUNCTION__ to determine the data type of the passed
* in expression to the function, during the runtime!
*/
template<typename T>
void foo(T value)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
foo(5);
foo(-9223372036854775808);
Compiling and running, I get this output: 编译并运行,我得到这个输出:
$ g++ -m64 -std=c++11 experiment2.cpp
$
$ ./a.out
void foo(T) [with T = int]
void foo(T) [with T = __int128]
I see that the passed in expression is of type __int128
. 我看到传入的表达式是
__int128
类型。 Apparently, this is a GNU compiler specific extension, not part of the C standard. 显然,这是GNU编译器特定的扩展,不是C标准的一部分。
Why isn't there int128_t? 为什么没有int128_t?
https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/_005f_005fint128.html https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/_005f_005fint128.html
https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/C-Extensions.html#C-Extensions https://gcc.gnu.org/onlinedocs/gcc-4.6.4/gcc/C-Extensions.html#C-Extensions
How is a 16 byte data type stored on a 64 bit machine 如何在64位机器上存储16字节数据类型
With all warnings enabled -Wall gcc will issue warning: integer constant is so large that it is unsigned
warning. 启用所有警告后,-all gcc将发出
warning: integer constant is so large that it is unsigned
警告。 Gcc assigns this integer constant the type __int128
and sizeof(__int128) = 16
. Gcc将此整数常量指定为
__int128
类型和sizeof(__int128) = 16
。
You can check that with _Generic macro: 您可以使用_Generic宏检查:
#define typestring(v) _Generic((v), \
long long: "long long", \
unsigned long long: "unsigned long long", \
__int128: "__int128" \
)
int main()
{
printf("Type is %s\n", typestring(-9223372036854775808));
return 0;
}
Type is __int128
Or with warnings from printf: 或者来自printf的警告:
int main() {
printf("%s", -9223372036854775808);
return 0;
}
will compile with warning: 将编译并发出警告:
warning: format '%s' expects argument of type 'char *', but argument 2 has type '__int128' [-Wformat=]
Your platform likely has __int128
and 9223372036854775808
is acquiring that type. 您的平台可能有
__int128
和9223372036854775808
正在获取该类型。
A simple way to get a C compiler to print a typename is with something like: 让C编译器打印类型名称的简单方法是:
int main(void)
{
#define LITERAL (-9223372036854775808)
_Generic(LITERAL, struct {char x;}/*can't ever match*/: "");
}
On my x86_64 Linux, the above is generating an error: '_Generic' selector of type '__int128' is not compatible with any association
error message, implying __int128
is indeed the type of the literal. 在我的x86_64 Linux上,上面产生了一个
error: '_Generic' selector of type '__int128' is not compatible with any association
错误消息error: '_Generic' selector of type '__int128' is not compatible with any association
,暗示__int128
确实是文字的类型。
(With this, the warning: integer constant is so large that it is unsigned
is wrong. Well, gcc isn't perfect.) (有了这个,
warning: integer constant is so large that it is unsigned
是错误的。好吧,gcc并不完美。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.