访问 args 而不传递它并避免全局变量

问题描述

void k() {
   I need argv here
}
void j() { k(); }
void h() { j(); }
void g() { h(); }
void f() { g(); }
void e() { f(); }
void d() { e(); }
void c() { d(); }
void b() { c(); }
void a() { b(); }
int main(int argc,char **argv) { a(); }

如何在我深入访问的函数 k 中访问命令行参数(作为向量或纯字符串)?我不想使用全局变量(这就是我现在实际做的并且想要避免的)。将它传递给每个功能也不是一个好的选择。实际上将它作为参数传递给从 ak 的所有函数是不可能的,因为某些函数是由库定义的,我无法更改它们的标题/代码。也许有 ANSI C 标准方法可以做到这一点?

解决方法

好吧,如果你不能把它作为函数参数传递,你需要某种静态存储,例如一个全局变量。

为了避免使它成为全局变量,您可以将它放入一个函数中,以便该变量对该函数来说是局部的。喜欢

char** get_argv(char** p)
{
    static char** s_argv = NULL;
    if (s_argv == NULL) s_argv = p; // Will set the static variable the first
                                    // time this function is called
                                    // After that it's "read only"
    return s_argv;
}

void b()
{
    char** argv = get_argv(NULL);      // This will read the static variable
    if (argv) printf("%s\n",argv[0]);
}

void a() { b(); }

int main(int argc,char **argv) 
{
    get_argv(argv);  // This will set the static variable inside the function get_argv
    a(); 
    return 0;
}
,

我能想到的唯一方法(不使用全局变量)是一直向下传递 argv:

void k(char **argv) {
   I need argv here
}
void j(char **argv) { k(argv); }
void h(char **argv) { j(argv); }
void g(char **argv) { h(argv); }
void f(char **argv) { g(argv); }
void e(char **argv) { f(argv); }
void d(char **argv) { e(argv); }
void c(char **argv) { d(argv); }
void b(char **argv) { c(argv); }
void a(char **argv) { b(argv); }
int main(int argc,char **argv) { a(argv); }
,

在 Linux(和 Solaris 11.4)上,您可以读取 /proc/self/cmdline(省略了错误检查和正确的标头包含指令以缩短示例并消除任何滚动条以提高可读性):

char **getArgv()
{
    int fd = open( "/proc/self/cmdline",O_RDONLY );
#ifdef sun
    struct stat sb;
    fstat( fd,&sb );
    size_t bytes = sb.st_size;
#else
    size_t bytes = getProcFileSize( fd );
#endif
    char *content = malloc( bytes );
    read( fd,content,bytes );
    close( fd );

    // count '\0' characters in file for number of args
    int argCount = 0;
    for ( int ii = 0; ii < bytesRead; ii++ )
    {
        if ( !content[ ii ] ) argCount++;
    }
    // add 1 for terminating NULL
    char **argv = calloc( argCount + 1,sizeof( *argv ) );

    // point argv values into content
    for ( int offset = 0,int arg = 0; arg < argCount; arg++ )
    {
        argv[ arg ] = &( content[ offset ] );
        offset += strlen( argv[ arg ] ) + 1;
    }

    return( argv );
}

要获取 Linux 上 cmdline 中的 /proc/ 等文件的大小,因为 [f|l]stat() 返回零:

size_t getProcFileSize( int fd )
{
    char buffer[ 1024 ];

    lseek( fd,SEEK_SET );
    size_t total = 0;
    for ( ;; )
    {
        ssize_t bytesRead = read( fd,buffer,sizeof( buffer ) );
        if ( bytesRead <= 0 )
        {
            break;
        }
        total += bytesRead;
    }

    lseek( fd,SEEK_SET );
    return( total );
}

免费:

void freeArgv( char **argv )
{
    // *argv (or argv[ 0 ]) points to
    // the content block allocated in getArgv()
    free( *argv );
    free( argv );
}

注意 - 我不确定哪个版本的 Solaris 11 是第一个在 cmdline 中包含 Linux 样式 /proc/[PID] 文件的版本。它在 11.4 中确实存在,而且我很确定它在 11.0 中不存在。