【问题标题】:Explain code in C [closed]解释 C 中的代码 [关闭]
【发布时间】:2012-11-22 07:20:59
【问题描述】:

我想了解这段代码,特别是 parse_args。这段代码就像运行 pwd cat 等基本 linux 命令的简单 shell。我想了解 parse_args 的工作原理。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/types.h>
#define BUFFER_SIZE 1<<16
#define ARR_SIZE 1<<16

void parse_args(char *buffer, char** args, 
                size_t args_size, size_t *nargs)
{
    char *buf_args[args_size]; /* You need C99 */
    char **cp;
    char *wbuf;
    size_t i, j;

    wbuf=buffer;
    buf_args[0]=buffer; 
    args[0] =buffer;

    for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
        if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
            break;
    }

    for (j=i=0; buf_args[i]!=NULL; i++){
        if(strlen(buf_args[i])>0)
            args[j++]=buf_args[i];
    }

    *nargs=j;
    args[j]=NULL;
}


int main(int argc, char *argv[], char *envp[]){
    char buffer[BUFFER_SIZE];
    char *args[ARR_SIZE];

    int *ret_status;
    size_t nargs;
    pid_t pid;

    while(1){
        printf("$ ");
        fgets(buffer, BUFFER_SIZE, stdin);
        parse_args(buffer, args, ARR_SIZE, &nargs); 

        if (nargs==0) continue;
        if (!strcmp(args[0], "exit" )) exit(0);       
        pid = fork();
        if (pid){
            printf("Waiting for child (%d)\n", pid);
            pid = wait(ret_status);
            printf("Child (%d) finished\n", pid);
        } else {
            if( execvp(args[0], args)) {
                puts(strerror(errno));
                exit(127);
            }
        }
    }    
    return 0;
}

【问题讨论】:

  • 你特别不明白的地方
  • 到目前为止你发现了什么?
  • 这个问题属于codereview.stackexchange.com
  • @icepack:我认为它不属于 CodeReview。它不是问如何改进它;它要求解释它的作用。

标签: c linux shell code-analysis


【解决方案1】:

这很有趣。该函数将缓冲区分隔为一个字符串数组,并在其中遇到一个空白分隔符。

void parse_args(char *buffer, char** args, 
                size_t args_size, size_t *nargs)
{
    char *buf_args[args_size]; /* You need C99 */
    char **cp;
    char *wbuf;
    size_t i, j;

初始化代码...

    wbuf=buffer;
    buf_args[0]=buffer; 
    args[0] =buffer;

将所有指针设置为缓冲区的开头

    for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
  1. 将写入指针cp 设置为指向buf_args 数组中的第一个元素。
  2. 将 *cp 设置为缓冲区中非空白标记的下一个实例,并将 wbuf 推进到其结束位置

        if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
            break;
    

当strsep返回NULL,或者当它指向缓冲区的末尾,或者当它指向超出buf_args[]的末尾时停止

    }

    for (j=i=0; buf_args[i]!=NULL; i++){
        if(strlen(buf_args[i])>0)
            args[j++]=buf_args[i];
    }

此循环创建 buf_args[] 数组的压缩副本:它仅复制非空字符串的参数。我想如果您的源缓冲区有一系列连续的空白字符,可能会发生这种情况。

    *nargs=j;
    args[j]=NULL;
}

在输出数组的末尾放置一个 NULL 并设置 nargs 输出参数。

【讨论】:

  • 你能准确解释一下 strsep ,例如 strlen 我插入这个命令 ls -al 这两个函数是如何工作的
【解决方案2】:

好的,让我们来看看 parse args 中的一些行

wbuf=buffer;
buf_args[0]=buffer; 
args[0] =buffer;

这会将wbuf 设置为指向buffer 中的内容。它还将buf_args 数组中的第一个指针设置为buffer。它对args 的第一个元素也做同样的事情。

for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
    if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
        break;
}

函数strsep 在wbuf 中查找分隔符空格、换行符或制表符,并返回指向标记开头的指针,wbuf 更新到标记的结尾。如果字符串中没有分隔符,则函数返回NULL。所以,for 语句的中间部分一直持续到*cp 等于NULL。

所以,指针cp 最初指向buf_args[0] 中的字符串(指针)。字符串分隔符函数用令牌的地址填充*cp。然后,if 语句检查 1) 如果 for 循环超过了 buf_args 的容量,通过检查指针 cp 是否超过最后一个元素和 2) 如果返回的令牌的第一个字符是字符串字符的结尾。

注意:我认为那行应该是*(*cp) != '\0'?

for (j=i=0; buf_args[i]!=NULL; i++){
    if(strlen(buf_args[i])>0)
        args[j++]=buf_args[i];
}

然后,它遍历所有buf_args,直到找到NULL。如果buf_args 指向的字符串长于0,即它有字符,则数组args 将获得指向令牌的指针的副本。

*nargs=j;
args[j]=NULL;

填充条目后args 的最后一个元素设置为NULL。而nargs的值设置为args数组中填充元素个数的长度。

【讨论】:

  • *cp != '\0' 条件可能只是写*cp != NULL 的一种有趣方式(它相当于那个)。 '\0' 是一个空指针常量,但不是普通的。
  • 我明白这一点,但是在一个程序中混合这样的符号很奇怪。
【解决方案3】:

在这段代码中

for(cp=buf_args; (*cp=strsep(&wbuf, " \n\t")) != NULL ;){
        if ((*cp != '\0') && (++cp >= &buf_args[args_size]))
            break;
 }

检查 wbuf 数组中的“\n\t”分隔符(首先是空格)并将其位置保存在 buf_args 然后在

for (j=i=0; buf_args[i]!=NULL; i++){
        if(strlen(buf_args[i])>0)
            args[j++]=buf_args[i];
    }

将参数提取到 args 数组以将结果从函数中提取出来的部分

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-05
    • 2014-02-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-10-01
    • 1970-01-01
    相关资源
    最近更新 更多