2016-11-14 9 views
4

printf가 넓은 문자 (wchar_t)와 어떻게 작동하는지 이해하려고합니다.printf로 넓은 문자 표시

샘플 1 :

#include <stdio.h> 
#include <stdlib.h> 

int  main(void) 
{ 
    wchar_t  *s; 

    s = (wchar_t *)malloc(sizeof(wchar_t) * 2); 
    s[0] = 42; 
    s[1] = 0; 
    printf("%ls\n", s); 
    free(s); 
    return (0); 
} 

출력 :

* 

모든 것이 여기 괜찮 : 내 문자 (*)이 제대로입니다

다음 코드 샘플을 만들었어요 표시됩니다.

샘플 2 :

다른 종류의 문자를 표시하고 싶습니다. 내 시스템에서 wchar_t은 4 바이트로 인코딩 된 것 같습니다. , s[0] (0xC389, 201 (참조, 이전 링크) É

#include <stdio.h> 
#include <stdlib.h> 

int  main(void) 
{ 
    wchar_t  *s; 

    s = (wchar_t *)malloc(sizeof(wchar_t) * 2); 
    s[0] = 0xC389; 
    s[1] = 0; 
    printf("%ls\n", s); 
    free(s); 
    return (0); 
} 

하지만이 시간, 나는 "인코딩"섹션에서 많은 값으로 시도 더 출력이없는 : 그래서 나는 다음과 같은 문자를 표시하려 0xC9) ... 그러나 나는 결코 É 문자를 표시하지 않습니다. 또한 %ls 대신 %S으로 시도했습니다.

printf를 다음과 같이 호출하려고하면 : printf("<%ls>\n", s) 인쇄 된 문자는 '<'이고 표시가 잘립니다.

왜이 문제가 있습니까? 어떻게해야합니까?

+0

두 요소의 배열을 선언하는 대신 동적으로 할당하는 이유가 있습니까? –

+0

'printf ("% lX \ n", (unsigned long) s [0])'에 대해'scanf ("% 1ls")'a' "É"'를 읽고 어떤 값을보고해라. – chux

+0

@chux'printf ("% ld \ n", (부호없는 long int) L' É ');'나에게'201'을줍니다. – vmonteco

답변

4

왜이 문제가 있습니까?

errno과 반환 값 printf을 확인하십시오!

#include <stdio.h> 
#include <stdlib.h> 
#include <wchar.h> 

int main(void) 
{ 
    wchar_t *s; 
    s = (wchar_t *) malloc(sizeof(wchar_t) * 2); 
    s[0] = 0xC389; 
    s[1] = 0; 

    if (printf("%ls\n", s) < 0) { 
     perror("printf"); 
    } 

    free(s); 
    return (0); 
} 

출력을 참조하십시오
$ gcc test.c && ./a.out 
printf: Invalid or incomplete multibyte or wide character 

어떻게 모든

첫째를 해결하기 위해, C 프로그램의 기본 로케일은 ASCII 전용입니다 (또한 POSIX라고도 함) C이다. setlocale (특히 setlocale(LC_ALL,""))에 전화를 추가해야합니다.

비어있을 때 LC_ALL, LC_CTYPE 또는 LANG 환경 변수가 UTF-8을 허용하도록 설정되지 않은 경우 명시 적으로 로케일을 선택해야합니다. setlocale(LC_ALL, "C.UTF-8")은 대부분의 시스템에서 작동합니다 (C). 일반적으로 UTF-8 하위 집합 인 C이 구현됩니다.

#include <stdio.h> 
#include <stdlib.h> 
#include <locale.h> 
#include <wchar.h> 

int main(void) 
{ 
    wchar_t *s; 
    s = (wchar_t *) malloc(sizeof(wchar_t) * 2); 
    s[0] = 0xC389; 
    s[1] = 0; 

    setlocale(LC_ALL, ""); 

    if (printf("%ls\n", s) < 0) { 
     perror("printf"); 
    } 

    free(s); 
    return (0); 
} 

출력 참조 :

$ gcc test.c && ./a.out 
쎉 

이유 이유 wchar_t은 UTF-등 (예를 UTF-32과 같은) 넓은 문자가 아닌 멀티 바이트 문자 (나타내므로 인쇄 잘못된 문자 인 8). wchar_t은 GNU C 라이브러리에서 항상 32 비트 폭이지만 C 표준에서는 필요하지 않습니다. 당신이 UTF-32BE 인코딩 (예 : 0x000000C9)를 사용하여 캐릭터를 초기화하는 경우, 그것은 올바르게 인쇄 :

#include <stdio.h> 
#include <stdlib.h> 
#include <locale.h> 
#include <wchar.h> 

int main(void) 
{ 
    wchar_t *s; 
    s = (wchar_t *) malloc(sizeof(wchar_t) * 2); 
    s[0] = 0xC9; 
    s[1] = 0; 

    setlocale(LC_ALL, ""); 

    if (printf("%ls\n", s) < 0) { 
     perror("printf"); 
    } 

    free(s); 
    return (0); 
} 

출력 : 당신은 또한을 통해 LC (로케일) 환경 변수를 설정할 수 있습니다

$ gcc test.c && ./a.out 
É 

주 명령 줄 :

$ LC_ALL=C.UTF-8 
$ ./a.out 
É 
3

단일 바이트 인코딩 체계 인 UTF-8을 멀티 바이트 인코딩으로 인코딩하려고 할 때 한 가지 문제가 있습니다. UTF-8의 경우 일반 char을 사용합니다.

또한 멀티 바이트 형식으로 UTF-8 시퀀스를 결합하려고하기 때문에, 당신은 endianness (바이트 순서) 문제 (메모리 0xC389에 순서대로, 0x890xC3로 저장 될 수있다)를 가지고 있습니다. 컴파일러에서 숫자를 부호 확장합니다 (sizeof(wchar_t) == 4이고 디버거에서 s[0]을 보면 0xFFFFC389 일 수 있음).

다른 문제는 인쇄하는 데 사용하는 터미널 또는 콘솔입니다. 어쩌면 UTF-8이나 다른 인코딩을 지원하지 않을 수도 있습니다.