当我这样做时:
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"
格式说明符存储为字符串文本,0xc(%ebp)
负责printf()
使用的实际值:
(gdb) x/db 0xbffff324
0xbffff324: -60
(gdb) p $al
$3 = -60
请注意,AL
(一个字节累加器,即.part 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;
}
我想这会给你你想要的。