首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >所有命令行参数都指向main

所有命令行参数都指向main
EN

Stack Overflow用户
提问于 2016-05-31 03:14:32
回答 2查看 240关注 0票数 2

我想知道主函数的所有命令行参数都是什么(特别是C语言,但我猜这将适用于所有语言,不管是什么语言)?在我的编译器类中,我听到一位讲师简短地提到(可能是我听错了,或者误解了这一点),说到main()参数比通常提到的要多,特别是在从argv指针的负值偏移时,我们可以访问一些信息。我在谷歌上搜索不到任何东西,在我的几本教科书里也找不到任何东西。我用C写了这个小程序来试一试。以下是一些问题:

1)在seg故障发生前循环运行32次。为什么总共有32个参数,我在哪里可以找到它们的说明?为什么有32个参数不是另一个量?

打印出来的信息都是关于系统的: pwd,术语会话信息,用户信息等等。

( 2)在main之前,有什么东西放在堆栈上吗?在典型的调用过程中,函数的参数放在返回地址之前的堆栈中(给或取金丝雀和其他东西)。当程序被shell调用时,进程是相同的,我在哪里可以读到这方面的内容?我真的很想知道shell是如何调用程序的,与程序中的堆栈布局相比,内存布局是什么。

代码语言:javascript
复制
#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;
}

非常感谢!很抱歉有个很长的邮件。

Update:以下是while循环的输出:

代码语言:javascript
复制
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
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2016-05-31 04:00:53

你好像在用Mac。在Mac电脑上,你可以得到4位数据。

您可以对以下的main()使用替代声明:

代码语言:javascript
复制
int main(int argcv, char **argv, char **envp)

然后,您将能够列出环境,就像您访问参数列表末尾之后所做的那样。环境遵循参数,并以空指针结束。

然后,Mac会在环境之后拥有更多的数据(您可以在输出中看到executable_path=… )。您可以在维基百科( 入境点 )下找到有关这方面的一些信息,后者指的是变元向量

代码语言:javascript
复制
int main(int argc, char **argv, char **envp, char **applev)

我不知道在argv向量之前有什么标准化。将它们作为单个字符访问是不太可能有用的。我会打印数据作为地址,并寻找模式。

这是几年前我为试图从environ中查找参数列表而编写的一些代码;它一直工作到通过添加一个新变量来修改环境为止,该变量更改了environ点所在的位置:

代码语言:javascript
复制
#include <inttypes.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>     /* putenv(), setenv() */

extern char **environ;  /* Should be declared in <unistd.h> */

/*
** The object of the exercise is: given just environ (since that is all
** that is available to a library function) attempt to find argv[0] (and
** hence argc).
**
** On some platforms, the layout of memory is such that the number of
** arguments (argc) is available, followed by the argument vector,
** followed by the environment vector.
**
**          argv                            environ
**            |                                |
**            v                                v
** | argc | argv0 | argv1 | ... | argvN | 0 | env0 | env1 | ... | envN | 0 |
**
** This applies to:
** -- Solaris 10 (32-bit, 64-bit SPARC)
** -- MacOS X 10.6 (Snow Leopard, 32-bit and 64-bit)
** -- Linux (RHEL 5 on x86/64, 32-bit and 64-bit)
**
** Sadly, this is not quite what happens on the other two Unix
** platforms.  The value preceding argv0 seems to be a 0.
** -- AIX 6.1          (32-bit, 64-bit)
** -- HP-UX 11.23 IA64 (32-bit, 64-bit)
**       Sub-standard POSIX support (no setenv()) and C99 support (no %zd).
**
** NB: If putenv() or setenv() is called to add an environment variable,
** then the base address of environ changes radically, moving off the
** stack onto heap, and all bets are off.  Modifying an existing
** variable is not a problem.
**
** Spotting the change from stack to heap is done by observing whether
** the address pointed to by environ is more than 128 K times the size
** of a pointer from the address of a local variable.
**
** This code is nominally incredibly machine-specific - but actually
** works remarkably portably.
*/

typedef struct Arguments
{
    char   **argv;
    size_t   argc;
} Arguments;

static void print_cpp(const char *tag, int i, char **ptr)
{
    uintptr_t p = (uintptr_t)ptr;
    printf("%s[%d] = 0x%" PRIXPTR " (0x%" PRIXPTR ") (%s)\n",
            tag, i, p, (uintptr_t)(*ptr), (*ptr == 0 ? "<null>" : *ptr));
}

enum { MAX_DELTA = sizeof(void *) * 128 * 1024 };

static Arguments find_argv0(void)
{
    static char *dummy[] = { "<unknown>", 0 };
    Arguments args;
    uintptr_t i;
    char **base = environ - 1;
    uintptr_t delta = ((uintptr_t)&base > (uintptr_t)environ) ? (uintptr_t)&base - (uintptr_t)environ : (uintptr_t)environ - (uintptr_t)&base;
    if (delta < MAX_DELTA)
    {
        for (i = 2; (uintptr_t)(*(environ - i) + 2) != i && (uintptr_t)(*(environ - i)) != 0; i++)
            print_cpp("test", i, environ-i);
        args.argc = i - 2;
        args.argv = environ - i + 1;
    }
    else
    {
        args.argc = 1;
        args.argv = dummy;
    }

    printf("argc    = %zd\n", args.argc);
    for (i = 0; i <= args.argc; i++)
        print_cpp("argv", i, &args.argv[i]);

    return args;
}

static void print_arguments(void)
{
    Arguments args = find_argv0();
    printf("Command name and arguments\n");
    printf("argc    = %zd\n", args.argc);
    for (size_t i = 0; i <= args.argc; i++)
        printf("argv[%zd] = %s\n", i, (args.argv[i] ? args.argv[i] : "<null>"));
}

static int check_environ(int argc, char **argv)
{
    size_t n = argc;
    size_t i;
    unsigned long delta = (argv > environ) ? argv - environ : environ - argv;
    printf("environ = 0x%lX; argv = 0x%lX (delta: 0x%lX)\n", (unsigned long)environ, (unsigned long)argv, delta);
    for (i = 0; i <= n; i++)
        print_cpp("chkv", i, &argv[i]);
    if (delta > (unsigned long)argc + 1)
        return 0;

    for (i = 1; i < n + 2; i++)
    {
        printf("chkr[%zd] = 0x%lX (0x%lX) (%s)\n", i, (unsigned long)(environ - i), (unsigned long)(*(environ - i)),
                (*(environ-i) ? *(environ-i) : "<null>"));
        fflush(0);
    }
    i = n + 2;
    printf("chkF[%zd] = 0x%lX (0x%lX)\n", i, (unsigned long)(environ - i), (unsigned long)(*(environ - i)));
    i = n + 3;
    printf("chkF[%zd] = 0x%lX (0x%lX)\n", i, (unsigned long)(environ - i), (unsigned long)(*(environ - i)));
    return 1;
}

int main(int argc, char **argv)
{
    printf("Before setting environment\n");
    if (check_environ(argc, argv))
        print_arguments();

    //putenv("TZ=US/Pacific");
    setenv("SHELL", "/bin/csh", 1);

    printf("After modifying environment\n");
    if (check_environ(argc, argv) == 0)
        printf("Modifying environment messed everything up\n");
    print_arguments();

    putenv("CODSWALLOP=nonsense");

    printf("After adding to environment\n");
    if (check_environ(argc, argv) == 0)
        printf("Adding environment messed everything up\n");
    print_arguments();

    return 0;
}
票数 2
EN

Stack Overflow用户

发布于 2016-05-31 03:47:31

在Linux上,*BSD --因此Mac -可能还有其他类似unix的系统,environ数组是在argv数组后面的堆栈上构造的。

environ将所有环境变量作为字符串数组包含在每个表单name=value中。虽然单个环境变量通常通过getenv函数访问,但也允许使用environ全局变量(通过Posix)。

main调用框架下的堆栈中查找这些字符串是不正确的,也没有提供比使用environ更多的优势。

如果您想查看实际代码,则需要深入研究execve系统调用的实现,这实际上是启动一个新进程的原因。关于Linux启动程序在lwn.org上的讨论看起来相当准确,其中包括指向代码存储库的指针。FreeBSD实现在许多方面类似于/sys/kern/kern_exec.c;您可能会开始阅读这里。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/37536280

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档