C ++编译器如何获取argv字符串的长度

c++ how does compiler get the length of argv strings

本文关键字:argv 字符串 获取 编译器 何获取      更新时间:2023-10-16

在 C/C++ 中,argc 是命令行参数的计数,argv 是字符**或指向字符指针的指针。我知道 argc 可以用来获取参数的数量,但是编译器如何知道第一个参数或第二个参数的长度?

编译器对argv的内容一无所知。 由编译器供应商提供并链接到可执行文件的运行时库将在创建进程时从操作系统获取命令行参数,然后该将分配自己的char*指针数组,这些指针指向从操作系统提供的数据复制的以 null 结尾的字符串。 然后,该数组通过argv传递到您的main()argc设置为数组中有效char*指针的数量。 运行时将在main()退出后为该数组释放内存。

与所有 C 字符串一样,argv指向的字符串以 0 结尾。

编译器不知道。(不能。当程序被调用一些实际参数时,编译器早已完成。但是该程序可以使用strlen找到。

操作系统通常将所有参数和环境字符串放在堆栈段上,正好在函数main()的第一个堆栈帧上方,然后argv数组也被堆叠,最后将argc变量传递给main()。 因为它们位于main()堆栈帧之上,因此代码也在用户空间中调用信号处理程序(信号处理程序确实在用户模式下执行(。 你隐藏了所有这些东西,因为你不需要知道它们在哪里。 这发生在linux和几乎所有Unix衍生产品中。 结构类似于:

  • 一种结构,允许外部程序知道参数列表和环境的开始位置,以访问堆栈的顶部。
  • 当系统返回到用户代码并且需要调用信号处理程序时调用信号处理程序的代码。 由于上述结构的长度是固定的,因此只需知道堆栈段的开始位置即可访问这两件事。
  • 所有环境字符串。 这是可变长度。
  • 所有命令行参数。 长度也可变。
  • 两个指针数组,第一个指针指向环境字符串的指针(格式为 "variable_name=value"(,第二个指针指向命令行参数(两个数组都以 和额外的NULL指针结尾,表示数组的结束(。
  • 对环境的指针引用(envp,遗留,C 标准没有说明环境可以作为第三个参数访问main()但一些遗留代码假设了这一点,所以我假设它仍在这样做(
  • 指向命令行数组的指针引用 (argc(
  • 命令行参数数为argvint
  • 要返回的main()返回值。

main()的参数通常作为返回指针上方的第一个和第二个参数进行访问。

这是调用main()的方式,它部分由操作系统填充(主要是字符串、数组、信号处理程序代码和定位指向参数和环境的指针的第一个结构(,然后控制运行时,部分由 C 标准运行时填充(argc参数计数,argv指针和envp指针(。 然后调用main(),将呼叫上的返回地址推送到main()

只是说这只是一种可能的实现,并且没有运行时被强制这样做,但是它是从pdp-11实现的遗留代码中假设的,因此在许多平台中仍然以这种方式实现。

检查此程序(它打印其命令行参数和环境(:

#include <stdio.h>
int main(int argc, char **argv, char **envp)
{
printf(
"%14p: argc(=%d)n"
"%14p: argvn"
"%14p: envpn",
&argc, argc,
&argv,
&envp);
printf(
"%14p: argv[]n"
"%14p: envp[]n",
argv,
envp);
int i;
for (i = 0; i <= argc; i++) {
printf("%2$14p: argv[%1$d] => "%2$s"n",
i, argv[i]);
}
for (i = 0; envp[i]; i++) {
printf("%2$14p: envp[%1$d] => "%2$s"n",
i, envp[i]);
}
/* .. and NULL environment final pointer */
printf("%2$14p: envp[%1$d] => "%2$s"n",
i, envp[i]);
return 0;
}

并用不同的参数列表调用它,看看它如何打印参数列表,然后打印环境字符串。

这是我系统上的呼叫输出:

$ a.out a b c | sort | less
0x0: argv[4] => "(null)"
0x0: envp[36] => "(null)"
0x7fffffffe368: envp
0x7fffffffe370: argv
0x7fffffffe378: argc(=4)
0x7fffffffe3f0: argv[]
0x7fffffffe418: envp[]
0x7fffffffe6f0: argv[0] => "pru72524"
0x7fffffffe6f9: argv[1] => "a"
0x7fffffffe6fb: argv[2] => "b"
0x7fffffffe6fd: argv[3] => "c"
0x7fffffffe6ff: envp[0] => "SHELL=/usr/local/bin/bash"
0x7fffffffe719: envp[1] => "WINDOWID=18874381"
0x7fffffffe72b: envp[2] => "XTERM_VERSION=XTerm(354)"
0x7fffffffe744: envp[3] => "TERMCAP=SC|screen|VT 100/ANSI X3.64 virtual termin>
0x7fffffffeaed: envp[4] => "JAVA_HOME=/usr/local/openjdk8"
0x7fffffffeb0b: envp[5] => "SSH_AUTH_SOCK=/tmp/ssh-0ssuWLqLKLsr/agent.1659"
0x7fffffffeb3a: envp[6] => "WINDOW=6"
0x7fffffffeb43: envp[7] => "ANT_HOME=/usr/local/share/java/apache-ant"
0x7fffffffeb6d: envp[8] => "SSH_AGENT_PID=1660"
0x7fffffffeb80: envp[9] => "XTERM_SHELL=/usr/local/bin/bash"
0x7fffffffeba0: envp[10] => "EDITOR=vi"
0x7fffffffebaa: envp[11] => "PWD=/home/lcu"
0x7fffffffebb8: envp[12] => "MAKEOBJDIRPREFIX=/home/lcu/obj"
0x7fffffffebd7: envp[13] => "LOGNAME=lcu"
0x7fffffffebe3: envp[14] => "TZ=Europe/Helsinki"
0x7fffffffebf6: envp[15] => "WINDOWPATH=9"
0x7fffffffec03: envp[16] => "LDFLAGS=-g"
0x7fffffffec0e: envp[17] => "HOME=/home/lcu"
0x7fffffffec1d: envp[18] => "LANG=es_ES.UTF-8"
0x7fffffffec2e: envp[19] => "XTERM_LOCALE=es_ES.UTF-8"
0x7fffffffec47: envp[20] => "TERM=screen"
0x7fffffffec53: envp[21] => "USER=lcu"
0x7fffffffec5c: envp[22] => "NETBEANS_HOME=/home/opt/netbeans"
0x7fffffffec7d: envp[23] => "MAVEN_HOME=/usr/local/share/java/maven"
0x7fffffffeca4: envp[24] => "DISPLAY=:0"
0x7fffffffecaf: envp[25] => "FORTUNE_PATH=/home/lcu/.fortune:/usr/share/games/>
0x7fffffffece8: envp[26] => "SHLVL=1"
0x7fffffffecf0: envp[27] => "PAGER=less -EFGRS"
0x7fffffffed02: envp[28] => "LD_LIBRARY_PATH=/home/lcu/lib:/home/lcu/lib:"
0x7fffffffed2f: envp[29] => "MAVEN_OPTS=-Xmx2048m"
0x7fffffffed44: envp[30] => "PATH=/home/lcu/bin:.:/usr/local/share/java/apache>
0x7fffffffef10: envp[31] => "STY=2430.pts-1.europa"
0x7fffffffef26: envp[32] => "BLOCKSIZE=K"
0x7fffffffef32: envp[33] => "CFLAGS=-g -O0 -DHAS_LIBUTIL_H"
0x7fffffffef50: envp[34] => "MAIL=/var/mail/lcu"
0x7fffffffef63: envp[35] => "_=./pru72524"
$ _