![](/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.