繁体   English   中英

MacOS中C程序的怪异行为

[英]Weird behaviour of C program in MacOS

我一直在用C编写Shell程序。该程序在Linux(Ubuntu 16.04)中按预期工作,但在MacOS(10.14.2 Mojave)中却得到了意外输出。

/* A shell program.
 */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>


void input(char* argv[]);
void print_arr(char *argv[]); // For debugging

int
main(void)
{
    while (1)
    {
        pid_t pid;
        char *argv[100];

        // Display shell prompt
        write(1, "(ash) $ ", 8);

        // Take user input
        input(argv);
        // print_arr(argv); // DEBUG STATEMENT

        if (argv[0] != NULL)
        {
            // Exit if exit command is entered
            if (strcmp(argv[0], "exit") == 0)
            {
                exit(0);
            }

            // Create child process
            if ((pid = fork()) > 0)
            {
                wait(NULL);
            }
            else if (pid == 0)
            {
                // print_arr(argv); // DEBUG STATEMENT

                execvp(argv[0], argv);
                printf("%s: Command not found\n", argv[0]);
                exit(0);
            }
            else
            {
                printf("Fork Error!\n");
            }
        }       
    }
}


/* Takes input from user and splits it in
   tokens into argv. The last element in
   argv will always be NULL. */
void
input(char* argv[])
{
    const int BUF_SIZE = 1024;
    char buf[BUF_SIZE];
    int i;

    buf[0] = '\0';
    fgets((void*) buf, BUF_SIZE, stdin);

    i = 0;
    argv[i] = strtok(buf, "  \n\0");
    while (argv[i] != NULL)
    {
        argv[++i] = strtok(NULL, "  \n\0");
    }
}

/* Print argv for debugging */
void
print_arr(char *argv[])
{
    int i = 0;
    while (argv[i] != NULL)
    {
        printf("%d: %s\n", i, argv[i]);
        ++i;
    }
}

在Linux中:

(ash) $ ls
// files and folders are listed

在MacOS(带有调试语句)中:

(ash) $ ls
0: p?M??
0: ??M??
: Command not found
(ash) $ ls
0: ls
0: ??M??
: Command not found
(ash) $ ls
0: ls
0: ??M??

我不明白为什么char* argv[]的内容在fork()被修改了?

我也在默认的clang编译器和brew的gcc-4.9尝试过,结果是一样的。

当程序无缘无故地表现出不同的行为时,这是未定义行为的非常好兆头。 这也是这里的原因。

数组buf对于函数input是本地的,并且在函数退出时不再存在。

解决此问题的一种方法是在main声明buf并将其传递给input 您还将需要fgets的缓冲区大小。

void
input(char * argv[], char * buf, size_t size)
{
    buf[0] = '\0';
    fgets(buf, sizeof buf, stdin);

    argv[0] = strtok(buf, "  \n\0");

    for(int i=0; argv[i] != NULL; i++) argv[i+1] = strtok(NULL, "  \n\0");
}

另一个解决方案(尽管我怀疑很多人BUF_SIZE )是将buf声明为static ,但是随后您将需要将BUF_SIZE更改为#define或硬编码值,因为您不能拥有静态VLA。

#define BUF_SIZE 1024
void
input(char * argv[])
{
    static char buf[BUF_SIZE];

    buf[0] = '\0';
    fgets(buf, sizeof buf, stdin);

    argv[0] = strtok(buf, "  \n\0");

    for(int i=0; argv[i] != NULL; i++) argv[i+1] = strtok(NULL, "  \n\0");
}

我删除了强制转换为void*因为它完全没有必要。 我也将while循环更改为for循环,以使循环变量在循环本地。

暂无
暂无

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

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