简体   繁体   English

什么是16字节有符号整数数据类型?“

[英]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 ^ 632 ^ 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. 您的平台可能有__int1289223372036854775808正在获取该类型。

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM