簡體   English   中英

什么是16字節有符號整數數據類型?“

[英]What is a 16 byte signed integer data type?"

我制作了這個程序來測試任意整數文字被評估的數據類型。 這個程序的靈感來自閱讀StackOverflow上的其他一些問題。

如何定義一個等於-2147483648的常量?

為什么我們將INT_MIN定義為-INT_MAX - 1?

(-2147483648> 0)在C ++中返回true?

在這些問題中,我們遇到了一個問題:程序員想要將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()是一個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 ^ 632 ^ 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編程語言中沒有這樣的數據類型。 我也不知道任何具有16字節寄存器的Intel x86_64處理器來存儲這樣的rvalue。 如果我錯了,請糾正我。 解釋這里發生了什么? 為什么沒有溢出? 此外,是否可以在C中定義一個16字節的數據類型? 你會怎么做?

經過一番挖掘,這就是我發現的。 我將代碼轉換為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標准的一部分。

為什么沒有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

如何在64位機器上存儲16字節數據類型

啟用所有警告后,-all gcc將發出warning: integer constant is so large that it is unsigned警告。 Gcc將此整數常量指定為__int128類型和sizeof(__int128) = 16
您可以使用_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

或者來自printf的警告:

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

將編譯並發出警告:

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

您的平台可能有__int1289223372036854775808正在獲取該類型。

讓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錯誤消息error: '_Generic' selector of type '__int128' is not compatible with any association ,暗示__int128確實是文字的類型。

(有了這個, 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