C

时间:2016-10-14 11:03:43

标签: c unix unicode

我正在学习UNIX系统编程。我正在为UNIX编写一个简单的shell应用程序(我在OS X Yosemite ver 10.10.5上使用Xcode)。我对C有过一些经验,但并不多。

实用程序工作正常并将打印unicode字符(虽然在Xcode控制台中打印' ????'而不是它,但它似乎是调试器本身的问题)。

我进行了一些研究,发现strcmp()也可以正常工作,只要它只是比较字节并最终查找零字节。读取输入也应该没问题,因为你只是读取字节。

我还读到unicode字符串不应该包含空字节。但是,在执行`strcmp()时,某些输入将导致EXC_BAD_ACCESS

代码:

阅读用户输入:

char* readCommand(void) {
    int buffer_size = LINE_BUFFER_SIZE;
    char *buffer = malloc(sizeof(char) * buffer_size);
    int position = 0;
    int character;

    if(!buffer)
    {
        fprintf(stderr, "readCommand failed: memory allocation error");
        exit(ALLOCATION_ERROR);
    }

    while (1) {
        character = getchar();
        if(character == EOF || character == '\n')
        {
            buffer[position] = '\0';
            char* cmd = buffer;
            free(buffer);
            return cmd;
        }
        else {
            buffer[position] = character;
        }
        if(++position >= sizeof(buffer))
        {
            buffer_size += LINE_BUFFER_SIZE;
            buffer = realloc(buffer, sizeof(char) * buffer_size);
            if(!buffer) {
                fprintf(stderr, "readCommand failed: memory reallocation error");
                free(buffer);
                exit(ALLOCATION_ERROR);
            }
        }
    }
    return NULL;
}

分裂args:

int split_string_quotes(char* source, char** argv, size_t arg_count)
{
    enum split_states state = DULL;
    char* p, *word_start = NULL;
    int character;
    int argc = 0;
    for(p = source; argc < arg_count && *p != '\0'; p++)
    {
        character = (unsigned char) *p;
        switch (state) {
            case DULL:
                if(isspace(character))
                {
                    continue;
                }
                if(character == '"')
                {
                    state = IN_STRING;
                    word_start = p+1;
                    continue;
                }
                state = IN_WORD;
                word_start = p;
                continue;

            case IN_WORD:
                if(isspace(character))
                {
                    state = DULL;
                    *p = 0;
                    argv[argc++] = word_start;
                }
                continue;

            case IN_STRING:
                if(character == '"')
                {
                    state = DULL;
                    *p = 0;
                    argv[argc++] = word_start;
                }
                continue;
        }
    }

    if(state != DULL && argc < arg_count)
    {
        argv[argc++] = word_start;
    }
    argv[argc] = NULL;
    return argc;
}

strcmp所在的地方:

int shell_execute(char **args)
{
    for(int i = 0; i < 3; i++)
    {
        if(strcmp(args[0], commands[i]) == 0)
        {
            return (*standardFuncs[i])(args);
        }
    }
    shell_launch(args);
    return 0;
}

主循环

    char* current_dir = malloc(sizeof(char)*PATH_MAX);
    char* args[MAX_ARGS];
    char* command;
    printf("dolphinShell (c) Alex Kale 2016\n");
    while (1)
    {
        getwd(current_dir);
        printf("dsh: %s-> ", current_dir);
        command = readCommand();
        printf("%s\n", command);
        split_string_quotes(command, args, MAX_ARGS);
        if(shell_execute(args) == -1) break;
    }
    free(current_dir);
    return 0;

所以,问题是我输入的一些unicode字符串工作正常并且永远不会导致EXC_BAD_ACCESS,但是当我输入фывпфвыапы时,它会中断。我认为问题在于访问args[0],但这是调试器的输出:

 Printing description of args:
    (char **) args = 0x00007fff5fbff900
    *args   char *  0x101800a00 0x0000000101800a00
    Printing description of *(*(args)):
    (char) **args = '\xd1'

所以它认为args[0]是空的,但它是空的吗?或者它被所有零混淆了吗?

我真的很困惑,我花了很多时间研究,似乎被困在这里。

我也尝试过使用wchar_twcscmp(),但它与execvp()无关,并且无法解决问题。

我也尝试了gcc -Wall -Wextra,输出结果如下:

main.c:53:26: warning: comparison of integers of different signs: 'int' and
      'size_t' (aka 'unsigned long') [-Wsign-compare]
    for(p = source; argc < arg_count && *p != '\0'; p++)
                    ~~~~ ^ ~~~~~~~~~
main.c:92:30: warning: comparison of integers of different signs: 'int' and
      'size_t' (aka 'unsigned long') [-Wsign-compare]
    if(state != DULL && argc < arg_count)
                        ~~~~ ^ ~~~~~~~~~
main.c:124:23: warning: comparison of integers of different signs: 'int' and
      'unsigned long' [-Wsign-compare]
        if(++position >= sizeof(buffer))
           ~~~~~~~~~~ ^  ~~~~~~~~~~~~~~
main.c:180:18: warning: unused parameter 'args' [-Wunused-parameter]
int dHelp(char **args)
                 ^
main.c:203:18: warning: unused parameter 'args' [-Wunused-parameter]
int dExit(char **args)
                 ^
main.c:210:14: warning: unused parameter 'argc' [-Wunused-parameter]
int main(int argc, const char** argv)
             ^
main.c:210:33: warning: unused parameter 'argv' [-Wunused-parameter]
int main(int argc, const char** argv)
                                ^
7 warnings generated.

但我认为不是这样(如果我错了,请纠正我)。

2 个答案:

答案 0 :(得分:2)

显示的代码中存在多个错误。

func performUpdateControl(){
    let reach = Reachability.reachabilityForInternetConnection()!
    if reach.isReachable() {
    work.getData()
    } else {
        UIAlertView(title: "Device without connection", message: "You must have an internet connection to use this feature", delegate: nil, cancelButtonTitle: "OK").show()
    }
    //add this        
    NSNotificationCenter.defaultCenter().postNotificationName("refreshCompleted", object: nil)
}

返回指向已删除 char* cmd = buffer; free(buffer); return cmd; 缓冲区的指针。继续使用此指针会导致未定义的行为。

char

if(++position >= sizeof(buffer)) buffer。这相当于:

char *

这将是4或8个字节,具体取决于您的硬件平台。每当缓冲区大于4或8字节时,就会不必要地调整缓冲区的大小。

您似乎相信 if(++position >= sizeof(char *)) 给出了sizeof() - ed缓冲区的大小。它没有。

总之:您的总体方法是编写一大堆代码,然后尝试查看它是否正常工作。这是错误的做法。你需要编写一个小函数。例如将一行读入缓冲区的那个。测试一下。验证它是否有效。现在您知道它可行了,继续前进并编写整个程序的下一个小部分。

答案 1 :(得分:0)

代码中的一个巨大错误就是您阅读输入的方式。看看这部分:

if(character == EOF || character == '\n')
{
    buffer[position] = '\0';
    char* cmd = buffer;
    free(buffer);
    return cmd;
}

在这里,您正在使用nil终止buffer,正如您所希望的那样。然后指定cmd指向buffer 相同的内存,释放缓冲区并将指针返回到已释放的内存。如果在此之后您使用返回的指针,则不允许任何事情发生任何事情。记忆可以在某个地方重复使用,你可以获得访问权限,也可能是你附近的火山爆发。

指定另一个变量的指针并不能复制内存,只是让它们指向同一个地方。在停止使用内容之前,您无法释放内存。这很可能会导致您的问题。