C语言中的unicode字符串比较

C语言中的unicode字符串比较,c,unix,unicode,C,Unix,Unicode,我正在学习UNIX系统编程。我正在为UNIX编写一个简单的shell应用程序(我在OS X Yosemite 10.10.5版上,使用Xcode)。我对C有一些经验,但不多 实用程序工作正常,可以打印unicode字符(虽然ls在Xcode控制台中打印“??”而不是它,但这似乎是调试器本身的问题) 我做了一些研究,发现strcmp()也可以很好地使用它,因为它只是比较字节,最后寻找一个零字节。读取输入也应该可以,因为您只读取字节 我还读到unicode字符串不应该包含空字节。但是,在执行'str

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

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

我做了一些研究,发现
strcmp()
也可以很好地使用它,因为它只是比较字节,最后寻找一个零字节。读取输入也应该可以,因为您只读取字节

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

代码:

读取用户输入:

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;
}
拆分参数:

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;
}
因此,问题在于,我键入的某些unicode字符串工作正常,不会导致
EXC_BAD_访问
,但当我键入
фыыПфщщП
时,它会中断。我认为问题在于访问
args[0]
,但调试器的输出如下:

 Printing description of args:
    (char **) args = 0x00007fff5fbff900
    *args   char *  0x101800a00 0x0000000101800a00
    Printing description of *(*(args)):
    (char) **args = '\xd1'
所以它认为
args[0]
是空的,但它是空的吗?还是被所有的零所迷惑

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

我也尝试过使用
wchar\u t
wcscmp()
,但它对
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.
main.c:53:26:警告:比较不同符号的整数:“int”和
'size_t'(也称为'unsigned long')[-Wsign compare]
对于(p=source;argc=sizeof(缓冲区))
~~~~~~~~~~ ^  ~~~~~~~~~~~~~~
main.c:180:18:警告:未使用的参数“args”[-Wunused参数]
int dHelp(字符**args)
^
main.c:203:18:警告:未使用的参数“args”[-Wunused参数]
int dExit(字符**args)
^
main.c:210:14:警告:未使用的参数“argc”[-Wunused参数]
int main(int argc,常量字符**argv)
^
main.c:210:33:警告:未使用的参数“argv”[-Wunused参数]
int main(int argc,常量字符**argv)
^
生成了7个警告。

但我认为情况并非如此(如果我错了,请纠正我)。

代码中的一个巨大缺陷是读取输入的方式。看看这部分:

if(character == EOF || character == '\n')
{
    buffer[position] = '\0';
    char* cmd = buffer;
    free(buffer);
    return cmd;
}
这里您应该使用nil终止
缓冲区
。然后指定
cmd
指向与
buffer
相同的内存,释放缓冲区并返回指向已释放内存的指针。如果在此之后,您使用返回的指针表示任何不允许的内容,并且任何事情都可能发生。内存可以在某个地方重复使用,您可能会遇到访问冲突,或者您附近的火山爆发


将指针赋给另一个变量并不会复制内存,它只会使它们指向同一个位置。在停止使用内容之前,无法释放内存。这很可能是导致您出现问题的原因。

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

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

        if(++position >= sizeof(buffer))
缓冲区
是一个
字符*
。这相当于:

        if(++position >= sizeof(char *))
这将是4或8字节,取决于您的硬件平台。每次缓冲区增长超过4或8字节时,都会调整缓冲区的大小,这是不必要的

您似乎相信
sizeof()
给出了
malloc
-ed缓冲区的大小。事实并非如此


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

“我做了一些研究,发现strcmp()也可以用它来工作,只要它只是比较字节,最后寻找零字节。读取输入也应该可以,因为你只读取字节。”-仅当您使用基于
char
的字符串(例如Ansi或UTF-8)读取输入时,才会出现这种情况。它不适用于读取为UTF-16/32的Unicode字符串。您需要
wchar\u t
来处理这些。此外,
args[0]
的调试器输出不会显示任何空内容
args[0]
(即
*args
)是数组中的第一个
char*
字符串指针,该指针在输出中不为空
**args
(即
args[0][0]
)是数组中第一个字符串中的第一个
char
,并且也不为空。它是
0xD1
,是UTF-8中Unicode
ф
字符的第一个字节(第二个字节是
0x84
)。
中的所有字符在UTF-8中各使用2个字节(因此
strlen(“фыыыыПфыщщщщщщщщщщщщщщщщщщщщщ109
在标准中定义为1。任何东西乘以1都没有效果。建议将该表达式从参数中删除到
malloc()
Ooh我明白了。真的应该是这样,不知道我怎么会错过那一次。我稍后再查,但我肯定那是p
        if(++position >= sizeof(buffer))
        if(++position >= sizeof(char *))