【发布时间】:2016-05-31 03:14:32
【问题描述】:
我想知道 main 函数的所有命令行参数是什么(特别是在 C 中,但我猜这无论如何都适用于所有语言)?在我的编译器课程中,我听到一位讲师简要提到(可能我听错或误解了)main() 参数比通常提到的要多,特别是在 argv 指针的负偏移量处,可以访问一些信息。我无法通过谷歌搜索或在我拥有的几本教科书中找到任何东西。我用C写了这个小程序来试试。以下是一些问题:
1) While 循环在段故障前运行 32 次。为什么总共有 32 个参数,我在哪里可以找到它们的规格,为什么其中 32 个不是另一个数量?
打印出来的信息都是关于系统的:密码、学期会话信息、用户信息等等。
2) 在 main 之前是否有任何东西被放入堆栈?在典型的调用过程中,函数的参数放在返回地址之前的堆栈中(给予或接受金丝雀和其他东西)。当一个程序被 shell 调用时,这个过程是一样的,我在哪里可以读到这个?我真的很想知道shell如何调用程序以及与程序内堆栈布局相比的内存布局是什么。
#include <stdio.h>
#include <ctype.h>
int main(int argc, char * argv[]) {
void * argall = argv[0];
printf("argc=%d\n", argc);
int i = 0;
while (i < 32) {
//while (argall) { // tried this to find out that it seg faults at i=32
printf("arg%d %s\n", i, (char* ) argall);
i++;
argall = argv[i];
}
printf("negative pointers\n");
// I don't think dereferencing in this part is quite right, but I am
// getting chars since I am reading bytes. Output of below code is.
// How come it is alphabet?
// I tried reading int values and (char*) for string, but got nothing useful.
/*
arg -1 o
arg -2 n
arg -3 m
arg -4 l
arg -5 k
*/
printf("arg -1 %c\n", (char) argv-1);
printf("arg -2 %c\n", (char) argv-2);
printf("arg -3 %c\n", (char) argv-3);
printf("arg -4 %c\n", (char) argv-4);
printf("arg -5 %c\n", (char) argv-5);
return 0;
}
非常感谢!很抱歉发了很长的帖子。
更新:这是来自 while 循环的输出:
argc=1
arg0 ./main-testing.o
arg1 (null)
arg2 TERM_PROGRAM=iTerm.app
arg3 SHELL=/bin/bash
arg4 TERM=xterm-256color
arg5 CLICOLOR=1
arg6 TMPDIR=/var/folders/d0/<redacted>
arg7 Apple_PubSub_Socket_Render=/private/<redacted>
arg8 OLDPWD=/Users/me/problems
arg9 USER=me
arg10 COMMAND_MODE=unix2003
arg11 SSH_AUTH_SOCK=/private/t<redacted>
arg12 _<redacted>
arg13 LSCOLORS=ExFxBxDxCxegedabagacad
arg14 PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin
arg15 PWD=/Users/me/problems/c
arg16 LANG=en_CA.UTF-8
arg17 ITERM_PROFILE=Default
arg18 XPC_FLAGS=0x0
arg19 PS1=\[\033[36m\]\u\[\033[m\]@\[\033[32m\]\h:\[\033[33;1m\]\w\[\033[m\]$
arg20 XPC_SERVICE_NAME=0
arg21 SHLVL=1
arg22 COLORFGBG=7;0
arg23 HOME=/Users/me
arg24 ITERM_SESSION_ID=w0t0p0
arg25 LOGNAME=me
arg26 _=./main-testing.o
arg27 (null)
arg28 executable_path=./main-testing.o
arg29
arg30
arg31
【问题讨论】:
-
你的导师的原话是什么?
argv之前没有任何“隐藏”参数。 -
我不太记得单词了,对不起。我的理解是在负偏移量的 argv 之前可以访问一些信息。我可能听错了,但我真的很古玩。因为我可以用负偏移量读取它,所以空间显然是我的(属于程序),所以我很想知道通过在堆栈上负数可以得到多远和什么。
-
在
i是0...argc的范围之外访问argv[i]是未定义的行为(UB)。而已。有时您可能会在某些机器上发现一些有用的东西,代码可能会崩溃。是UB。 C 并没有指定代码尝试时会发生什么。 -
对不起,什么是UB?谢谢。
-
未定义行为。你不能只访问内存的随机位并从中得出结论。仅仅因为它直到某个点才崩溃并不意味着数据是有效的(尽管其中一些确实发生在您的情况下)。也就是说,你的前提和结论是有缺陷的。话虽如此,在某些情况下,C 标准确实为
main定义了第三个参数:“char *envp[],它指向一个以空结尾的指向 char 的指针数组,每个指针都指向一个提供信息的字符串关于这个程序执行的环境”