2016-11-08 5 views
-2

Mein Setup: glibc 2.24, gcc 6.2.0, UTF-8-Umgebung.Warum übergeben Sie char als Parameter an islower() nicht korrekt?

Wenn wir islower() in der folgenden test.c aufrufen, wird das Ergebnis korrekt gedruckt:

#include <locale.h> 
#include <ctype.h> 
#include <stdio.h> 
int main (void) 
{ 
    setlocale(LC_ALL, "fr_FR.ISO-8859-1"); 
    if (islower(0xff)) return 0; 
    return 1; 
} 
$ gcc -g -o test test.c 
$ ./test; echo $? 
0 

Jetzt 0xff-'ÿ', wir und test2.c ändern erhalten:

#include <locale.h> 
#include <ctype.h> 
#include <stdio.h> 
int main (void) 
{ 
    setlocale(LC_ALL, "fr_FR.ISO-8859-1"); 
    if (islower('ÿ')) return 0; 
    return 1; 
} 

Obwohl der Ausgang sollsein, wie in test.c, es ist anders:

$ gcc -g -fexec-charset=iso8859-1 -o test2 test2.c 
$ ./test2; echo $? 
1 

Die iso8859-1 locale richtig installiert ist:

$ locale -a 
C 
C.UTF-8 
en_US.utf8 
french 
fr_FR 
fr_FR.iso88591 
POSIX 

Weder strace noch gdb etwas Nützliches zu offenbaren.

Unten ist ein Strace-Ausgang für test und test2.


execve("./test", ["./test"], [/* 43 vars */]) = 0 
brk(NULL)        = 0x557a2ad1a000 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f13c7e91000 
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=98552, ...}) = 0 
mmap(NULL, 98552, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f13c7e78000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0755, st_size=1685264, ...}) = 0 
mmap(NULL, 3791264, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f13c78d4000 
mprotect(0x7f13c7a69000, 2093056, PROT_NONE) = 0 
mmap(0x7f13c7c68000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x194000) = 0x7f13c7c68000 
mmap(0x7f13c7c6e000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f13c7c6e000 
close(3)        = 0 
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f13c7e76000 
arch_prctl(ARCH_SET_FS, 0x7f13c7e76700) = 0 
mprotect(0x7f13c7c68000, 16384, PROT_READ) = 0 
mprotect(0x557a29abe000, 4096, PROT_READ) = 0 
mprotect(0x7f13c7e94000, 4096, PROT_READ) = 0 
munmap(0x7f13c7e78000, 98552)   = 0 
brk(NULL)        = 0x557a2ad1a000 
brk(0x557a2ad3b000)      = 0x557a2ad3b000 
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=3517584, ...}) = 0 
mmap(NULL, 3517584, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f13c7579000 
close(3)        = 0 
exit_group(0)       = ? 
+++ exited with 0 +++ 
execve("./test2", ["./test2"], [/* 43 vars */]) = 0 
brk(NULL)        = 0x5603a66f6000 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
mmap(NULL, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f24d23c4000 
access("/etc/ld.so.preload", R_OK)  = -1 ENOENT (No such file or directory) 
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=98552, ...}) = 0 
mmap(NULL, 98552, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f24d23ab000 
close(3)        = 0 
access("/etc/ld.so.nohwcap", F_OK)  = -1 ENOENT (No such file or directory) 
open("/lib/x86_64-linux-gnu/libc.so.6", O_RDONLY|O_CLOEXEC) = 3 
read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0\320\3\2\0\0\0\0\0"..., 832) = 832 
fstat(3, {st_mode=S_IFREG|0755, st_size=1685264, ...}) = 0 
mmap(NULL, 3791264, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x7f24d1e07000 
mprotect(0x7f24d1f9c000, 2093056, PROT_NONE) = 0 
mmap(0x7f24d219b000, 24576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x194000) = 0x7f24d219b000 
mmap(0x7f24d21a1000, 14752, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x7f24d21a1000 
close(3)        = 0 
mmap(NULL, 8192, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x7f24d23a9000 
arch_prctl(ARCH_SET_FS, 0x7f24d23a9700) = 0 
mprotect(0x7f24d219b000, 16384, PROT_READ) = 0 
mprotect(0x5603a560b000, 4096, PROT_READ) = 0 
mprotect(0x7f24d23c7000, 4096, PROT_READ) = 0 
munmap(0x7f24d23ab000, 98552)   = 0 
brk(NULL)        = 0x5603a66f6000 
brk(0x5603a6717000)      = 0x5603a6717000 
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3 
fstat(3, {st_mode=S_IFREG|0644, st_size=3517584, ...}) = 0 
mmap(NULL, 3517584, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7f24d1aac000 
close(3)        = 0 
exit_group(1)       = ? 
+++ exited with 1 +++ 

Warum test2 nicht zurück 0?

+0

Was bedeutet 'printf ("% d ", 'ÿ');' printf? –

+0

@MichaelWalz es druckt '-1', aber wie soll ich' islower() 'auf dem Zeichen' ÿ' nennen? Es stellt sich heraus, dass 'islower ('a');' ist legal, aber 'islower ('ÿ');' ist nicht? Das ist ein schlechtes Design. –

Antwort

1

Die Frage läuft darauf hinaus:

Wenn ich dies schreibe:

int x = 'ÿ'; 

x wird -1, aber ich möchte es 255.

Es ist -1 weil 'ÿ' sein ist ein char von Wert 0xff. Aber da char auf Ihrer Plattform signiert ist, findet die Zeichenerweiterung statt, wenn Sie sie einer int zuweisen.

Die Lösung ist, zu schreiben:

int x = (unsigned char)'ÿ'; 

Also statt islower('ÿ') schreiben islower((unsigned char)'ÿ').

+0

Aus dieser Antwort folgt, dass der Typ "char" standardmäßig vorzeichenlos sein muss, da er gemäß seinem Namen zum Speichern von ** char ** acters verwendet wird. Können Sie sich einen bestimmten Grund vorstellen, der gcc-Entwickler daran gehindert hat, unsigned als Standard für 'char' zu verwenden? –

+0

@IgorLiferenko Blick auf [diese Frage SO] (http://stackoverflow.com/questions/2054939/is-char-signed-or-unsigned-by-default). –

Verwandte Themen