私はUNIXシステムプログラミングを学んでいます。 UNIX用のシンプルなシェルアプリケーションを作成しています(OS X Yosemite ver 10.10.5を使用していますが、Xcodeを使用しています)。私はCで少し経験しましたが、あまりありませんでした。Cでユニコード文字列を比較
ユーティリティプログラムは正常に動作し、Unicode文字を出力します(ただし、lsはXcodeコンソールでは代わりに「????」を表示しますが、デバッガ自体の問題であるようです)。
私はちょっとした研究をして、strcmp()
もバイトを比較して最後にゼロバイトを探している限り、うまく動作することがわかりました。読み込み入力は、バイトを読み込むだけでOKです。
また、ユニコード文字列にnullバイトが含まれていないことも読んでいます。しかし、 `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;
}
スプリット引数:strcmpのがどこにあるのです
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;
}
:
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_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.
しかし、私はそれはケース(私が間違っているなら、私を修正)だとは思いません。
http://www.joelonsoftware.com/articles/Unicode.html – Biffen
"*私は少しの調査をして、strcmp()もバイトと比較していればうまく動作するはずであることを知りました。最後にゼロバイトを探します。読み込み入力もちょうどバイト読み込みのように "+" - これはAnsiまたはUTF-8の 'char'ベースの文字列を使用して入力を読み込んでいる場合にのみ当てはまります。例えば。代わりにUTF-16/32として読み込まれるUnicode文字列では機能しません。それらを処理するには 'wchar_t'が必要です。 –
また、 'args [0]'のデバッガ出力に何も表示されません。 'args [0]'(つまり '* args')は、配列中の最初の' char * '文字列ポインタであり、出力ではNULLではありません。 '** args'(つまり' args [0] [0] ')は配列の最初の文字列の最初の' char'であり、NULLでもありません。 '0xD1'は、UTF-8のUnicode'ф'文字の最初の**バイト**です(その2番目の**バイト**は '0x84 'です)。 'фывпфвыапы'の文字はすべてUTF-8で2バイトずつ使用されます(したがって' strlen( "фывпфвыапы")はUTF-8では20であり、10ではありません)。 –