代码之家  ›  专栏  ›  技术社区  ›  Galaxy

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

  •  3
  • Galaxy  · 技术社区  · 6 年前

    我做了这个程序来测试什么数据类型的任意整型文字得到评估。这个程序是从阅读有关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 实际上是字面意思 - 是一元求反运算符。因为int_max通常 2^31-1个 有32位int的 2 ^ 31 不能表示为 int ,因此它被提升为更大的数据类型。第三个问题的第二个答案有一个图表,根据该图表可以确定整型文字的数据类型。编译器从顶部向下搜索列表,直到找到适合文本的数据类型。

    Suffix Decimal constants none int long int long long int

    ======================================================

    在我的小程序中,我定义了一个宏,它将以C字符串的形式返回变量、文本或表达式的“名称”。基本上,它返回在宏内部传递的文本,正如您在代码编辑器中看到的那样。我用它来打印文本表达式。

    我想确定表达式的数据类型,它的计算结果。我必须对我怎么做有点聪明。如何在C语言中确定变量或表达式的数据类型?我得出的结论是,只有两个“位”的信息是必要的:以字节为单位的数据类型的宽度和数据类型的签名性。

    我使用 sizeof() 以字节为单位确定数据类型宽度的运算符。我还使用另一个宏来确定数据类型是否有符号。 typeof() 是返回 数据类型 变量或表达式的。但我不能 阅读 数据类型。我打字 -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 如果我们能相信图表。众所周知, 双长整型 具有数值范围 - 2 ^ 63 2^63-1个 在现代64位系统上。但是, - 上面是一元求反运算符,不是整型文字的一部分。我正在尝试确定 2 ^ 63 太大了 双长整型 . 我正试图在C的类型系统中引起一个错误。这是故意的,而且只是为了教育目的。

    我正在编译和运行这个程序。我用 -std=gnu99 而不是 -std=c99 因为我在用 类型(共) 是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编程语言中没有这样的数据类型。我也不知道任何一个Intelx86_64处理器有一个16字节的寄存器来存储这样一个值。如果我错了请纠正我。解释这里发生了什么?为什么没有溢出?此外,是否可以在C中定义16字节的数据类型?你会怎么做?

    3 回复  |  直到 6 年前
        1
  •  3
  •   Petr Skocik    6 年前

    你的平台可能有 __int128 9223372036854775808 正在获取该类型。

    让C编译器打印字体名的一个简单方法是:

    int main(void)
    {
    
        #define LITERAL (-9223372036854775808)
        _Generic(LITERAL, struct {char x;}/*can't ever match*/: "");
    
    }
    

    在我的x86_64 Linux上,上面生成了一个 error: ‘_Generic’ selector of type ‘__int128’ is not compatible with any association 错误消息,暗示 _国际128 确实是文本的类型。

    (有了这个, warning: integer constant is so large that it is unsigned 是错误的。嗯,GCC并不完美。)

        2
  •  3
  •   Galaxy    6 年前

    在挖了一些洞之后,这就是我发现的。我把代码转换成C++,假设C和C++在这种情况下的行为类似。我想创建一个模板函数来接受任何数据类型。我用 __PRETTY_FUNCTION__ 这是一个GNU编译器扩展,它返回一个包含函数“原型”的C字符串,我的意思是返回类型、名称和输入的形式参数。我对形式参数感兴趣。使用这种技术,我可以确定表达式的数据类型,而不需要猜测!

    /**
     * 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);
    

    编译并运行,我得到这个输出:

    $ g++ -m64 -std=c++11 experiment2.cpp
    $
    $ ./a.out
    void foo(T) [with T = int]
    void foo(T) [with T = __int128]
    

    我看到传入表达式的类型为 __int128 . 显然,这是GNU编译器特定的扩展,不是C标准的一部分。

    Why isn't there 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/C-Extensions.html#C-Extensions

    How is a 16 byte data type stored on a 64 bit machine

        3
  •  3
  •   KamilCuk    6 年前

    启用所有警告后-墙GCC将发出 warning: integer constant is so large that it is unsigned 警告。gcc将这个整型常量赋给 __int128 sizeof(__int128) = 16 .
    您可以使用_generic macro进行检查:

    #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
    

    或有来自printf的警告:

    int main() {
        printf("%s", -9223372036854775808);
        return 0;
    }
    

    将编译并发出警告:

    warning: format '%s' expects argument of type 'char *', but argument 2 has type '__int128' [-Wformat=]