簡體   English   中英

為什么使用char agrv而不是char ** argv作為main的參數導致以下輸出?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM