繁体   English   中英

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

[英]c++ how does compiler get the length of argv strings

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

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

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

编译器不知道。 (它不能。当用一些实际的 arguments 调用程序时,编译器早就完成了。)但是程序可以使用strlen找到。

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

  • 一种结构,允许外部程序知道参数列表和环境从哪里开始,以访问堆栈顶部。
  • 当系统返回到用户代码并且需要调用信号处理程序时调用信号处理程序的代码。 由于上述结构的长度是固定的,因此只需知道堆栈段的开始位置就可以访问这两个内容。
  • 所有环境字符串。 这是可变长度。
  • 所有命令行参数。 还有变长。
  • Two arrays of pointers, the first with pointers to the environment strings (in the form "variable_name=value") and the second to the command line arguments (both arrays are ended with and extra NULL pointer signalling the end of the array).
  • 对环境的指针引用( envp , legacy , C 标准不 state 环境可以作为main()的第三个参数访问,但一些旧代码假定,所以我认为它仍在这样做)
  • 指向命令行数组 ( argc ) 的指针引用
  • 一个int ,带有argv的命令行 arguments 的编号。
  • main()要返回的返回值。

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

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

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

检查这个程序(它打印它的命令行 arguments 和环境):

#include <stdio.h>

int main(int argc, char **argv, char **envp)
{
    printf(
        "%14p: argc(=%d)\n"
        "%14p: argv\n"
        "%14p: envp\n",
        &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;
}

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

这是我系统上用于呼叫的 output:

$ 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"
$ _

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM