我撰寫了一段代碼,用于研究不同庫和函式的行為。這樣做,我偶然發現了 sscanf 的一些奇怪行為。
我有一段代碼將輸入讀入緩沖區,然后嘗試將該值放入數字變數中。
當我使用輸入緩沖區從 main 呼叫 sscanf 時,如果輸入字串比緩沖區短,格式說明符 %x 會產生一個垃圾值。假設我輸入 0xff,我每次都會得到一個任意大的亂數。但是當我將該緩沖區傳遞給函式時,所有對 scanf 的呼叫都會像我預期的那樣導致 255 (0xff),無論型別和格式說明符不匹配。
我的問題是,為什么這發生在函式 main 而不是函式測驗中?
這是代碼:
#include <stdio.h>
int test(char *buf){
unsigned short num;
unsigned int num2;
unsigned long long num3;
sscanf(buf, "%x", &num);
sscanf(buf, "%x", &num2);
sscanf(buf, "%x", &num3);
printf("%x", num);
printf("%x", num2);
printf("%x", num3);
return 0;
}
void main(){
char buf[16];
unsigned long long num;
printf("%s","Please enter the magic number:");
fgets(buf, sizeof(buf),stdin);
sscanf(buf, "%x", &num);
printf("%x\n", num);
test(&buf);
}
我希望這種行為具有凝聚力;所有呼叫都應該失敗,或者所有呼叫都應該成功,但事實并非如此。
我嘗試閱讀檔案并使用不同的型別、格式說明符等進行實驗。此行為存在于所有數字型別中。
我試過在不同的平臺上編譯;gcc 和 Linux 的行為相同,Windows 和 msvc 也是如此。
我還反匯編了二進制檔案,看看 main() 和 test() 對 sscanf 的呼叫是否不同,但該程式集是相同的。它將指向緩沖區的指標加載到暫存器中并將該暫存器壓入堆疊,并呼叫 sscanf。
現在要明確一點:這種情況始終如一,main 中的 num 永遠不會等于 test 中的 num、num2 或 num3,但 num、num2 和 num3 總是彼此相等。我希望這會導致未定義的行為并且不一致。運行時輸出 - 每次
./main
Please enter the magic number: 0xff
0xaf23af23423 <--- different every time
0xff <--- never different
0xff <--- never different
0xff <--- never different
我目前的推理是在一個實體中 sscanf 解釋的位元組數比另一個實體多。它似乎一直在評估整個緩沖區,受到記憶體中殘留資料的影響。
我知道我可以通過填充緩沖區(將最后一個位元組作為新行)或使用正確的格式說明符來匹配指標型別來使其行為正確。在這種情況下,“%llx”代表 main。所以這不是我想知道的;我是故意犯這個錯誤的。
我想知道為什么在代碼運行時使用錯誤的格式說明符在一種情況下有效,而在另一種情況下卻不一致。
uj5u.com熱心網友回復:
sscanfwith只能與 的地址一起%x使用。當傳遞另一個物件的地址時,C 標準沒有定義該行為。unsigned int
使用指向更寬物件的指標,物件中的附加位元組可能包含其他值(可能是啟動代碼準備行程并呼叫時剩余的main)。使用指向較窄物件的指標,sscanf可能會在物件之外寫入位元組。通過編譯器優化,可以實作多種附加行為。這些不同的可能性可能表現為大量、資料損壞、程式崩潰或其他行為。
此外,使用不正確的轉換說明符進行列印不是由 C 標準定義的,并且在printf嘗試處理傳遞給它的引數時可能會導致錯誤。
用于%hx掃描成unsigned short. 用于%lx掃描成unsigned long. 用于%llx掃描成unsigned long long. 在列印相應型別時也使用這些轉換說明符。
我的問題是,為什么這發生在函式 main 而不是函式測驗中?
num一種可能性是啟動代碼在設定行程時使用了一點堆疊空間,這在后來用于in的位元組中留下了一些非零資料main。堆疊中較低的位元組保持零值,這些位元組后來用于num3in test。
uj5u.com熱心網友回復:
此呼叫中的引數運算式
test(&buf);
具有型別char ( * )[16],但函式需要該型別的引數char *
int test(char *buf){
這些指標型別之間沒有隱式轉換。
你需要像這樣呼叫函式
test( buf );
而且好像有錯別字
printf("%s","Please enter the magic number:");
printf("%x\n", num);
變數num未初始化。
在這次通話中
unsigned long long num;
//...
sscanf(buf, "%x", &num);
您正在使用 type 的第三個引數,unsigned long long int *但轉換規范"%x"需要 type 的引數unsigned int *。所以呼叫具有未定義的行為。
你需要寫
sscanf(buf, "%llx", &num);
num具有型別的已使用變數存在相同的問題unsigned short
unsigned short num;
//...
sscanf(buf, "%x", &num);
你必須寫
sscanf(buf, "%hx", &num);
您需要在 printf 呼叫中使用相同的長度修飾符
printf("%hx", num);
printf("%x", num2);
printf("%llx", num3);
這是一個演示程式。
#include <stdio.h>
int main( void )
{
char buf[] = "0xff\n";
unsigned short num;
unsigned int num2;
unsigned long long num3;
sscanf( buf, "%hx", &num );
sscanf( buf, "%x", &num2 );
sscanf( buf, "%llx", &num3 );
printf( "%hx\n", num );
printf( "%x\n", num2 );
printf( "%llx\n", num3 );
}
程式輸出為
ff
ff
ff
轉載請註明出處,本文鏈接:https://www.uj5u.com/net/530474.html
上一篇:列印除數之和最高的數字
