[英]Adding an signed integer beyond 0xFFFFFFFF
#include <stdio.h>
void fun3(int a, int b, int c)
{
printf("%d \n", a+b+c );
}
void fun2 ( int x, int y)
{
fun3(0x33333333,0x30303030, 0x31313131);
printf("%d \n", x+y);
}
fun1 (int x)
{
fun2(0x22222222,0x20202020);
printf("%d \n", x);
}
main()
{
fun1(0x1111111);
}
我正在通過上面的程序進行堆棧破壞。 我正在使用某些不希望的值獲取上述程序的o / p。 我所能理解的是,如果相加的值超出0xFFFFFFFF,則較小的負整數變為最大值,即-1變為0xFFFFFFFF。 關於此的任何見解
到@Cornstalks的要點: INT_MIN
為0x80000000
, (int)-1
為2的補碼(無論如何在32位系統上(int)-1
為0xFFFFFFFF
。
這使指令集可以執行帶符號算術的操作,例如:
1 + -2 = -1
成為(為簡短起見,以符號short
開頭)
0x0001 + 0xFFFE = 0xFFFF
... 然后:
1 + -1 = 0
在內部以溢出表示為
0x0001 + 0xFFFF = 0x0000
另外,@ Cornstalks指出:內部表示(以及溢出添加)是實現細節。 C實現(和指令集)不需要用2的補碼表示整數,因此為有符號整數類型提供十六進制值可能會使您陷入C實現的子集。
編輯(更正) (我錯過了要點。我的答案是對常數的,但問題包含函數的參數,那么這里發生的是有符號整數對象的溢出,並且正如他的注釋中正確指出的@Cornstalks一樣,這是未定義的行為)。 /編輯
在fun1()
您以錯誤的方式使用了printf()
。
您編寫了"%d"
以接受一個int
,但是如果您的數字大於MAX_INT
,則情況並非如此。
您必須檢查系統中的MAX_INT
的值。
如果您以十六進制格式編寫整數常量,則標准C(ISO C99或C11)將按照以下順序嘗試將值放入該常量可以容納的第一種類型:
int,unsigned int,long int,unsigned long int,long long int,unsigned long long int。
因此,如果您的常數大於MAX_INT
( int
范圍內的最大值),則您的常數(如果為正)的類型為unsigned int
,但指令%d
期望有signed int
值。 因此,將示出一些負數。
最糟糕的是,如果常量的值大於UMAX_INT
( unsigned int
范圍內的unsigned int
),則常量的類型將是long int, unsigned long int, long long int
,其精度嚴格大於of unsigned int
。
這意味着%d
變成一個錯誤的指令。
如果您不能完全確定自己的值將是多少,可以將其強制轉換為最大的整數類型:
printf("%lld", (long long int) 0x33333333333);
指令%lld
表示long long int
。
如果您始終對正值感興趣,則必須使用%llu
並將其%llu
為unsigned long long int
:
printf("%llu", (unsigned long long int) 0x33333333333);
通過這種方式,你避免了“搞笑”的數字,高達,你看大號碼不丟失任何精度。
備注:常量INT_MAX
, UINT_MAX
等位於limits.h中 。
重要提示:管型的自動順序僅適用於八進制和十六進制常量。 對於十進制常量,還有另一條規則:
int,long int,long long int。
fun3
將嘗試打印值0x94949494。 這大於最大的4個字節的整數值0x7FFFFFFF,因此它將“溢出”,並且(如果在今天制造的幾乎每台計算機上,)我都會正確生成負數-0x6B6B6B6C(如果我正確地做了算術的話),即-1802201964。
fun1
和fun2
應該顯示“預期”的積極結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.