![](/img/trans.png)
[英]Why is main() argument argv of type char*[] rather than const char*[]?
[英]Why does using char agrv instead of char **argv as the argument of main cause the following output?
當我這樣做:
int main(int agrc, char argv)
{
printf("%d", argv);
return 0;
}
當我從命令行運行程序時,我收到此輸入:
$ prog_name 0
0
$ prog_name (from 0-7 characters)
48
$ prog_name 12345678
56
$ prog_name 1234567812345678
64
// and so on...
那么這些值來自何處以及它們為何增加8?
當我這樣做時會發生什么:
int main(int agrc, char argv[])
?
您的輸出可能是“普通” argv
參數的地址,這是
隱式轉換
解釋, 請參閱下面的注釋為char
。 換句話說,我懷疑你所擁有的相當於:
int main(int agrc, char **argv)
{
printf("%d", (char) argv);
return 0;
}
在我的機器上(CentOS 6 32位)反匯編的目標代碼如下:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: and $0xfffffff0,%esp
0x080483ca <+6>: sub $0x10,%esp
0x080483cd <+9>: mov 0xc(%ebp),%eax
0x080483d0 <+12>: movsbl %al,%eax
0x080483d3 <+15>: mov %eax,0x4(%esp)
0x080483d7 <+19>: movl $0x80484b4,(%esp)
0x080483de <+26>: call 0x80482f4 <printf@plt>
和您發布的原始代碼:
0x080483c4 <+0>: push %ebp
0x080483c5 <+1>: mov %esp,%ebp
0x080483c7 <+3>: and $0xfffffff0,%esp
0x080483ca <+6>: sub $0x20,%esp
0x080483cd <+9>: mov 0xc(%ebp),%eax
0x080483d0 <+12>: mov %al,0x1c(%esp)
0x080483d4 <+16>: movsbl 0x1c(%esp),%eax
0x080483d9 <+21>: mov %eax,0x4(%esp)
0x080483dd <+25>: movl $0x80484b4,(%esp)
0x080483e4 <+32>: call 0x80482f4 <printf@plt>
在這兩種情況下, $0x80484b4
將"%d"
格式說明$0x80484b4
存儲為字符串文字, 0xc(%ebp)
負責printf()
使用的實際值:
(gdb) x/db 0xbffff324
0xbffff324: -60
(gdb) p $al
$3 = -60
請注意, AL
(一個字節累加器,即EAX
一部分)僅在$ebp+0xc
地址處“取出”第一個字節(我的CPU是小端,因此它實際上是LSB)。 這意味着(char)
轉換會“切斷” argv
地址。
因此,您可能會發現這些數字中的每一個都沒有設置log2(n)
最低有效位。 這是由於指針類型對象的對齊要求。 通常對於32位x86機器alignof(char **) == 4
。
正如評論中已經指出的那樣,你違反了C標准,所以這是UB的一個例子。
從C標准來看,關於main()
的簽名
該實現聲明此函數沒有原型。
因此,如果傳遞不同類型的參數,編譯器將不會出現任何問題。
在你的代碼中,
int main(int agrc, char argv)
不是main()
推薦的簽名。 它應該是
int main(int agrc, char* argv[])
或至少
int main(int agrc, char** argv)
否則,在托管環境中,行為未定義。 您可以在C11
標准的第5.1.2.2.1章中查看更多內容。
在您的情況下,如您所見,您將第二個參數設置為char
類型。 根據標准規范,
如果
argc
的值大於零,則數組成員argv[0]
到argv[argc-1]
包含指向字符串的指針,....
因此,這里,提供的0
作為指向字符串的指針傳遞給main()
,該字符串在char
被接受,這不是已定義的行為。
還有就是堆棧上的字符串的指針,但你申報main
有焦炭那里,然后打印它作為一個小數。 該字符串的內存地址是不可預測的,因此您將獲得不可預測的輸出。
嘗試這個:
int main( int argc, char* argv[] )
{
printf( "%s", argv[1] );
return 0;
}
我想這會給你你的意圖。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.