C상의 char는 8-bit를 나타내는 자료형으로 기능합니다. "문자열"이라는 것은 \0으로 끝나고 " "안에 표현되는 바이트 열이 되고요.
US-ASCII의 경우 signed char(=char), 즉 부호 있는 7비트 자료형으로 표현이 가능합니다(범위 0x20-0x7f)이것이 ISO-8859-1과 같은 8비트가 모두 필요한 자료형이 된다면 unsigned char가 필요하게 되고요(두번째의 답변). 하지만 둘 다 8비트 바이트 단위의 자료형입니다. 그리고 기본적으로 1바이트 = 1문자 또는 알파벳, 기호라는 인식에 근거하고 있습니다.
멀티바이트와 와이드 바이트는 이러한 자료형으로 표현할 수 없는 다른 나라의 언어(한중일은 물론 다른 아시아, 인도, 일부 유럽 등)를 표현하기 위한 방법입니다. 차이점이라고 한다면
- 멀티 바이트는 "한 문자가 1 또는 그 이상의 바이트로 표현됨"
- 와이드 바이트는 "한 문자가 일정 크기의 바이트의 배열로 표현됨"
입니다. 간단한 예를 들어 보면, "C언어"라는 문자열을 멀티바이트로 표현하면
"C"(1바이트), "언"(2바이트) "어"(2바이트) = 총 5바이트
와 같이 문자에 따라 바이트 수가 다릅니다. 와이드바이트에서 한 문자를 표시하기 위해 필요한 바이트 수는 여러가지가 있습니다만 glibc에서는 4바이트를 쓰므로 가정하면,
"C" (4바이트), "언"(4바이트), "어"(4바이트) = 총 12바이트
로 표현이 됩니다. 표준으로 따지만 멀티바이트는 ISO-2022에 가깝고(euc-kr 등), 와이드 바이트는 ISO-10646(유니코드)에 가깝습니다. wchar_t는 와이드 바이트를 나타내는 자료형인데, glibc라면 unsigned long(32비트)로 선언되어 있고 유니코드 정보를 담게 됩니다. 멀티바이트의 경우 특별한 자료형 보다는 그냥 unsigned/signed char의 포인터를 사용하게 됩니다. C99에는 와이드바이트 지원이 언어 수준에서 포함된 것으로 알고 있고, VC++의 경우도 와이드바이트 문자열과 멀티바이트 문자열을 구분하고 있습니다(상수 문자열에 L을 붙이면 와이드바이트 상수 문자열이 됩니다. e.g. L"C언어"와 "C언어"의 차이).
이런 쓸 데 없는 코드(?)가 있고, 한글이 euc-kr, cp949 같은 code로 작성되어 있다면, strstr 이 예상하지 않은 결과를 보내게 됩니다.
이런 것을 방지하려면, strstr 대신 wcswcs, wcsstr 등의 함수들(platform마다 다릅니다)을 사용해야합니다. 그러기 위해서는 mbs를 wcs 로 바꿔야하지요.
-------------
아래 질문에는 두가지 문제가 있는 것 같군요.
하나는 char *는 unsigned char *냐 signed char * 이냐 이구요.
다른 하나는 " " 는 const char * 이냐, char * 이냐입니다.
" "안에 들어있는 상수는 char* (=signed char*)이지만 각 상수를 가리키는 포인터는 signed/unsigned char* 이므로, 위 동작으로는 다른 것이 없지만 안의 내용을 문자단위로 비교하려 할 때에는 signed나 unsigned냐에 따라서 달라집니다. 가령 편의상 다음과 같이 하였다면,
glibc에서 wcs는 32비트(4바이트) 이더군요
그렇다면 mbs를 wcs 로 변환할때 몇바이트를 한문자로 간주할것인지는
어떻게 결정이 되나요 ? 현재 locale 에 따라서 결정이 되나요 ?
mbs에 저장된 문자열이 한글이라면 프로그램을 짤때
setlocale(LC_ALL, "ko_KR");
를 꼭 줘야 하는지요 ?
그리고 추가적인 질문 하나만 더드리자면
제가 UTF-8로 인코딩된 txt문서를 처리하려고 하는데
이 문서를 읽어들일떄
char*에 저장해서 처리하는것이 맞는지
wchar_t*에 저장해서 처리하는것이 맞는지
아니면 char*에 저장한구 wchar_t로 변환을 해야 하는지
아니면 iconv로 euc_kr로 변환한후 char*에 저장해야 하는지.
에고 정말 복잡하군요.. 조언 부탁드립닏.ㅏ
cjh wrote:
C상의 char는 8-bit를 나타내는 자료형으로 기능합니다. "문자열"이라는 것은 \0으로 끝나고 " "안에 표현되는 바이트 열이 되고요.
US-ASCII의 경우 signed char(=char), 즉 부호 있는 7비트 자료형으로 표현이 가능합니다(범위 0x20-0x7f)이것이 ISO-8859-1과 같은 8비트가 모두 필요한 자료형이 된다면 unsigned char가 필요하게 되고요(두번째의 답변). 하지만 둘 다 8비트 바이트 단위의 자료형입니다. 그리고 기본적으로 1바이트 = 1문자 또는 알파벳, 기호라는 인식에 근거하고 있습니다.
멀티바이트와 와이드 바이트는 이러한 자료형으로 표현할 수 없는 다른 나라의 언어(한중일은 물론 다른 아시아, 인도, 일부 유럽 등)를 표현하기 위한 방법입니다. 차이점이라고 한다면
- 멀티 바이트는 "한 문자가 1 또는 그 이상의 바이트로 표현됨"
- 와이드 바이트는 "한 문자가 일정 크기의 바이트의 배열로 표현됨"
입니다. 간단한 예를 들어 보면, "C언어"라는 문자열을 멀티바이트로 표현하면
"C"(1바이트), "언"(2바이트) "어"(2바이트) = 총 5바이트
와 같이 문자에 따라 바이트 수가 다릅니다. 와이드바이트에서 한 문자를 표시하기 위해 필요한 바이트 수는 여러가지가 있습니다만 glibc에서는 4바이트를 쓰므로 가정하면,
"C" (4바이트), "언"(4바이트), "어"(4바이트) = 총 12바이트
로 표현이 됩니다. 표준으로 따지만 멀티바이트는 ISO-2022에 가깝고(euc-kr 등), 와이드 바이트는 ISO-10646(유니코드)에 가깝습니다. wchar_t는 와이드 바이트를 나타내는 자료형인데, glibc라면 unsigned long(32비트)로 선언되어 있고 유니코드 정보를 담게 됩니다. 멀티바이트의 경우 특별한 자료형 보다는 그냥 unsigned/signed char의 포인터를 사용하게 됩니다. C99에는 와이드바이트 지원이 언어 수준에서 포함된 것으로 알고 있고, VC++의 경우도 와이드바이트 문자열과 멀티바이트 문자열을 구분하고 있습니다(상수 문자열에 L을 붙이면 와이드바이트 상수 문자열이 됩니다. e.g. L"C언어"와 "C언어"의 차이).
glibc에서 wcs는 32비트(4바이트) 이더군요
그렇다면 mbs를 wcs 로 변환할때 몇바이트를 한문자로 간주할것인지는
어떻게 결정이 되나요 ? 현재 locale 에 따라서 결정이 되나요 ?
맞습니다. multibyte의 경우도 OS에 따라 내부 표현방식이 달라질 수 있습니다.
Quote:
mbs에 저장된 문자열이 한글이라면 프로그램을 짤때
setlocale(LC_ALL, "ko_KR");
를 꼭 줘야 하는지요 ?
locale-dependent한 함수를 쓰신다면 그렇게 해야 겠지요. 정확한 카테고리로 치면 LC_CTYPE입니다.
Quote:
그리고 추가적인 질문 하나만 더드리자면
제가 UTF-8로 인코딩된 txt문서를 처리하려고 하는데
이 문서를 읽어들일떄
char*에 저장해서 처리하는것이 맞는지
wchar_t*에 저장해서 처리하는것이 맞는지
아니면 char*에 저장한구 wchar_t로 변환을 해야 하는지
아니면 iconv로 euc_kr로 변환한후 char*에 저장해야 하는지.
UTF-8은 어느쪽인가 하면 multibyte에 가깝습니다. 한글자가 1-6바이트 정도로 표현될 수 있으니까요. 보통은 unsigned char*에 넣으시고 필요하면 iconv()로 변환해서 쓰시면 됩니다.
1. open() -> fopen()
2. fopen()과 iconv_open()을 각각 fclose()와 iconv_close()로 닫으세요.
3. iconv()의 3, 5번째 인수는 각각 입력 버퍼의 크기, 출력 버퍼의 크기입니다. 함수 수행 후에 변환된 만큼(중간에 중단될 수도 있으므로) 입력 버퍼의 크기와 출력 버퍼의 크기가 변환된 만큼 감소합니다.
1. 위에 제 코드에서처럼 변환문자열의 끝에 NULL Terminator는 수동으로 붙여줘야 하는지요 ?
2. 이건 좀 iconv랑은 별개질문인데, 제 시스템이 FreeBSD4.7입니다.
iconv 라이브러리 헤더랑 라이브러리가 각각 /usr/local/include, /usr/local/lib 밑에 있더라구요
전 이것들도 당연히 표준 라이브러리/헤더 디렉토리인줄 알았는데 포함이 안되는것 같더라구요
그래서 아래와 같이 컴파일 했거든요
1. 위에 제 코드에서처럼 변환문자열의 끝에 NULL Terminator는 수동으로 붙여줘야 하는지요 ?
2. 이건 좀 iconv랑은 별개질문인데, 제 시스템이 FreeBSD4.7입니다.
iconv 라이브러리 헤더랑 라이브러리가 각각 /usr/local/include, /usr/local/lib 밑에 있더라구요
전 이것들도 당연히 표준 라이브러리/헤더 디렉토리인줄 알았는데 포함이 안되는것 같더라구요
그래서 아래와 같이 컴파일 했거든요
2.1. 현재 컴파일러에서 표준헤더/라이브러리 디렉토리를 볼수 있는방법은 ?
2.2. -I -L directive를 쓰지 않고 전역적으로 이 디렉토리들을 링커에 추가해 주는 방법은 ?
이상입니다. 한번만 더 도와주세요 :oops:
1. null terminator는 자동으로 붙네요.
2.1. 표준 헤더 디렉토리는... gcc 컴파일할때 스펙에 있었겠지만 /usr/include 이고 라이브러리는 /usr/lib입니다.
2.2. 전역적으로 디렉토리를 추가할 필요가 없습니다. 그냥 그렇게 쓰시면 되고요... 정 필요하시면 고쳐서 gcc/binutils를 다시 빌드하면 되겠지만... 그것보다는 해당 파일을 /usr/include와 /usr/lib에 복사하는 수도 있겠지요.
C상의 char는 8-bit를 나타내는 자료형으로 기능합니다. "문자열"
C상의 char는 8-bit를 나타내는 자료형으로 기능합니다. "문자열"이라는 것은 \0으로 끝나고 " "안에 표현되는 바이트 열이 되고요.
US-ASCII의 경우 signed char(=char), 즉 부호 있는 7비트 자료형으로 표현이 가능합니다(범위 0x20-0x7f)이것이 ISO-8859-1과 같은 8비트가 모두 필요한 자료형이 된다면 unsigned char가 필요하게 되고요(두번째의 답변). 하지만 둘 다 8비트 바이트 단위의 자료형입니다. 그리고 기본적으로 1바이트 = 1문자 또는 알파벳, 기호라는 인식에 근거하고 있습니다.
멀티바이트와 와이드 바이트는 이러한 자료형으로 표현할 수 없는 다른 나라의 언어(한중일은 물론 다른 아시아, 인도, 일부 유럽 등)를 표현하기 위한 방법입니다. 차이점이라고 한다면
- 멀티 바이트는 "한 문자가 1 또는 그 이상의 바이트로 표현됨"
- 와이드 바이트는 "한 문자가 일정 크기의 바이트의 배열로 표현됨"
입니다. 간단한 예를 들어 보면, "C언어"라는 문자열을 멀티바이트로 표현하면
"C"(1바이트), "언"(2바이트) "어"(2바이트) = 총 5바이트
와 같이 문자에 따라 바이트 수가 다릅니다. 와이드바이트에서 한 문자를 표시하기 위해 필요한 바이트 수는 여러가지가 있습니다만 glibc에서는 4바이트를 쓰므로 가정하면,
"C" (4바이트), "언"(4바이트), "어"(4바이트) = 총 12바이트
로 표현이 됩니다. 표준으로 따지만 멀티바이트는 ISO-2022에 가깝고(euc-kr 등), 와이드 바이트는 ISO-10646(유니코드)에 가깝습니다. wchar_t는 와이드 바이트를 나타내는 자료형인데, glibc라면 unsigned long(32비트)로 선언되어 있고 유니코드 정보를 담게 됩니다. 멀티바이트의 경우 특별한 자료형 보다는 그냥 unsigned/signed char의 포인터를 사용하게 됩니다. C99에는 와이드바이트 지원이 언어 수준에서 포함된 것으로 알고 있고, VC++의 경우도 와이드바이트 문자열과 멀티바이트 문자열을 구분하고 있습니다(상수 문자열에 L을 붙이면 와이드바이트 상수 문자열이 됩니다. e.g. L"C언어"와 "C언어"의 차이).
--
익스펙토 페트로눔
아래와 같은 용어를 사용하겠습니다. 주로 함수에서 사용되는 표기법입니다.
아래와 같은 용어를 사용하겠습니다. 주로 함수에서 사용되는 표기법입니다.
mb : multi byte character
wc : wide char
mbs : multibyte string
wcs : wide char string
mb와 wc 는 상호 변환 함수가 있습니다. 이때는, locale에 관련된 환경변수가 영향을 주게 되지요. 환경변수에 따라 mbs중에 어떤 경계로 mb들을 를 해석하는 지 내부 shared object(dll)들이 다르게 불려집니다.
wide character가 사용되는 것은 다음과 같은 이유때문입니다.
if ( strstr( "프린터", "존") != 0 )
{
printf("프린터에서 존이 발견됩니다.");
}
이런 쓸 데 없는 코드(?)가 있고, 한글이 euc-kr, cp949 같은 code로 작성되어 있다면, strstr 이 예상하지 않은 결과를 보내게 됩니다.
이런 것을 방지하려면, strstr 대신 wcswcs, wcsstr 등의 함수들(platform마다 다릅니다)을 사용해야합니다. 그러기 위해서는 mbs를 wcs 로 바꿔야하지요.
-------------
아래 질문에는 두가지 문제가 있는 것 같군요.
하나는 char *는 unsigned char *냐 signed char * 이냐 이구요.
다른 하나는 " " 는 const char * 이냐, char * 이냐입니다.
컴파일러마다 다르다라고만 알려드릴뿐 자세한 것은
찾아봐야 할 것같습니다.
---
http://coolengineer.com
Re: 멀티바이트캐릭터와 와이트캐릭터는 뭐가 다른가요 ?
" "안에 들어있는 상수는 char* (=signed char*)이지만 각 상수를 가리키는 포인터는 signed/unsigned char* 이므로, 위 동작으로는 다른 것이 없지만 안의 내용을 문자단위로 비교하려 할 때에는 signed나 unsigned냐에 따라서 달라집니다. 가령 편의상 다음과 같이 하였다면,
두 문자열을 printf()하는 정도로는 다른게 없지만, 비교하면 문제가 생깁니다.
다음 코드를 직접 실행해 보시고 왜 그런 결과가 나오는지 생각해 보시면 쉽게 알 수 있을 것입니다.
p.s. wc관련 함수는 일부 다를 수 있지만 UNIX나 Windows나 거의 동일하게 제공하고 있습니다. 윈도우에서는 별도의 함수군을 제공하기는 합니다만.
--
익스펙토 페트로눔
그렇다면 wcs에서 몇바이트를 한문자로 간주할것인지는 어디서
glibc에서 wcs는 32비트(4바이트) 이더군요
그렇다면 mbs를 wcs 로 변환할때 몇바이트를 한문자로 간주할것인지는
어떻게 결정이 되나요 ? 현재 locale 에 따라서 결정이 되나요 ?
mbs에 저장된 문자열이 한글이라면 프로그램을 짤때
를 꼭 줘야 하는지요 ?
그리고 추가적인 질문 하나만 더드리자면
제가 UTF-8로 인코딩된 txt문서를 처리하려고 하는데
이 문서를 읽어들일떄
char*에 저장해서 처리하는것이 맞는지
wchar_t*에 저장해서 처리하는것이 맞는지
아니면 char*에 저장한구 wchar_t로 변환을 해야 하는지
아니면 iconv로 euc_kr로 변환한후 char*에 저장해야 하는지.
에고 정말 복잡하군요.. 조언 부탁드립닏.ㅏ
Re: 그렇다면 wcs에서 몇바이트를 한문자로 간주할것인지는 어디
맞습니다. multibyte의 경우도 OS에 따라 내부 표현방식이 달라질 수 있습니다.
locale-dependent한 함수를 쓰신다면 그렇게 해야 겠지요. 정확한 카테고리로 치면 LC_CTYPE입니다.
UTF-8은 어느쪽인가 하면 multibyte에 가깝습니다. 한글자가 1-6바이트 정도로 표현될 수 있으니까요. 보통은 unsigned char*에 넣으시고 필요하면 iconv()로 변환해서 쓰시면 됩니다.
--
익스펙토 페트로눔
죄송합니다 마지막 질문입니다
실력이 딸려서 참 힘들군요. 마지막으로 이론이 아니라 예제로서 여쭤보겟습니다.
한마디로 제가 하려는일은 UTF-8로 인코딩되어 있는 파일을읽어서 EUC-KR 로 변환해서 콘솔로 출력하는 일입니다.
먼저
이렇게 "질문맨" 이라는 글자가 들어있는 utf-8 인코딩 파일을 만들었습니다
이제 저는 이 utf.txt를 읽어들여서 콘솔에서 다시 euc-kr로 변한시켜 출력하고 싶습니다. 아래와 같이 프로그램을 짜봤습니다.
이렇게 하면제대로 다시 디코딩된 "질문맨" 이라는 글짜가 나올줄 알았는데
깨진 글자들이 나오네요
제 코드에서 잘못된 부분을지적해 주실수 있으세요 ?
그리고 iconv() 에서 3, 5 번째 아규먼트인
inbytesleft, outbytesleft에 어떠한 값을 넣어야 하는지 간단한설명도부탁좀
제가영어가 짧아서 잘 이해가 안되네요
감사합니다.
[code:1]printf("%s\n", o
대신에
이렇게 해야 맞습니다.
테스트 안해봐서리 문법error가 나는지는 모르겠군요.
iconv에 넣을 때, 원본 변수와 번역본 변수를 직접넣지 않고
pointer를 취해서 넣는 것은, iconv가 그 값을 shift해서 이동시키기 때문입니다.
따라서, 위에서 outbuffer 값은 최종적으로는 outary의 비어있는 부분을 가리키게 됩니다.
---
http://coolengineer.com
1. open() -> fopen()2. fopen()과 ico
1. open() -> fopen()
2. fopen()과 iconv_open()을 각각 fclose()와 iconv_close()로 닫으세요.
3. iconv()의 3, 5번째 인수는 각각 입력 버퍼의 크기, 출력 버퍼의 크기입니다. 함수 수행 후에 변환된 만큼(중간에 중단될 수도 있으므로) 입력 버퍼의 크기와 출력 버퍼의 크기가 변환된 만큼 감소합니다.
--
익스펙토 페트로눔
드디어 결과물에 성공은 했습니다. 몇가지 추가질문좀...
제 집요한 질문에 귀찮아 하시지 않고 답변해 주신
두분께 정말 감사드리고요. 제 최종코드는 아래와 같이 출력결과물에 성공했습니다.
추가로 질문 몇개만 드려도 될까요 ?
1. 위에 제 코드에서처럼 변환문자열의 끝에 NULL Terminator는 수동으로 붙여줘야 하는지요 ?
2. 이건 좀 iconv랑은 별개질문인데, 제 시스템이 FreeBSD4.7입니다.
iconv 라이브러리 헤더랑 라이브러리가 각각 /usr/local/include, /usr/local/lib 밑에 있더라구요
전 이것들도 당연히 표준 라이브러리/헤더 디렉토리인줄 알았는데 포함이 안되는것 같더라구요
그래서 아래와 같이 컴파일 했거든요
제 질문은
2.1. 현재 컴파일러에서 표준헤더/라이브러리 디렉토리를 볼수 있는방법은 ?
2.2. -I -L directive를 쓰지 않고 전역적으로 이 디렉토리들을 링커에 추가해 주는 방법은 ?
이상입니다. 한번만 더 도와주세요 :oops:
Re: 드디어 결과물에 성공은 했습니다. 몇가지 추가질문좀...
1. null terminator는 자동으로 붙네요.
2.1. 표준 헤더 디렉토리는... gcc 컴파일할때 스펙에 있었겠지만 /usr/include 이고 라이브러리는 /usr/lib입니다.
2.2. 전역적으로 디렉토리를 추가할 필요가 없습니다. 그냥 그렇게 쓰시면 되고요... 정 필요하시면 고쳐서 gcc/binutils를 다시 빌드하면 되겠지만... 그것보다는 해당 파일을 /usr/include와 /usr/lib에 복사하는 수도 있겠지요.
--
익스펙토 페트로눔
1. 스펙에 없다면 마직막 변환 끝 버퍼엔 \0을 넣는 것은 수동으로 해
1. 스펙에 없다면 마직막 변환 끝 버퍼엔 \0을 넣는 것은 수동으로 해주어야합니다.
2. 다른 질문에 대한 답변으로 한 것이 있는데..
http://bbs.kldp.org/viewtopic.php?t=4597
참조하세요
---
http://coolengineer.com
댓글 달기