Chapter 25. International Features

지환·2022년 3월 21일
0

C를 international 하게 만들기 위해 다양한 언어를 지원해야 됐었고, 1994년에 이런 특징을 좀 포함한 Amendment 1 이 승인됐다. 그리고 C99에서 international features이 더 추가됐다.


25.1 The <locale.h> Header

Localization
이 header는 "locale에 따라 행동이 달라지는 library"를 control하는 함수를 제공한다.

library의 Locale-dependent 측면은 아래와 같다.
1) Formatting of numerical quatities : 소숫점을 .으로 쓰기도 하고, ,로 쓰기도 한다.
2) Formatting of monetary quantities
3) Character set
4) Appearance of date and time : 달을 먼저 적기도하고, 날짜를 먼저 적기도 한다.

Categories

locale을 변경할때, library의 모든 parts를 다 변경할 필요는 없다.
이를 위해 category인 아래 macro를 사용할 수 있다.

  1. LC_COLLATE
    : strcollstrxfrm에 영향 (<string.h>)

  2. LC_CTYPE
    : <ctype.h>의 함수들(isdigit, isxdigit 제외)에 영향
    multibyte와 wide-character functions에도 영향

  3. LC_MONETARY
    : localeconv 함수로부터 반환된 monetary formatting information에 영향

  4. LC_NUMERIC
    : formatted I/O에 쓰인 decimal-point character에 영향
    numeric conversion functions (ex. stdtod)에 영향(in <stdlib.h>)
    localeconv 함수로부터 반환된 monetary formatting information에 영향

  5. LC_TIME
    : time을 character string으로 바꾸는 strftime 함수(<time.h>)에 영향
    wcsftime함수에 영향

Implementationdl LC_ macro를 추가로 정의해도 된다.

The setlocale Function

setlocale

char *setlocale(int category, const char *locale);

하나 혹은 전체의 category에 대해 현재 locale을 변경한다.

첫번째 인자는 위에서 말한 특정 category나 LC_ALL(전체를 의미)이 올 수 있다.

두번째 인자는 표준에서 "C""" 두개만 정의하고 있다. 나머지는 implementation defined.
"C"가 오면, "normal way"로 작동한다.(decimal point는 .)
""가 오면 native locale로 바뀐다. program이 local environment에 맞게 행동한다.

하지만 Standard는 native locale로 바뀌는 것에 대한 정확한 효과에 대해 정의하진 않았다.
어떤 implementations은 execution environment를 확인해서 바꾸고(getenv),
어떤 implementations은 아무것도 안한다.(대신 잘 팔리진 않겠네)

Return 값은
성공시 : 새로운 locale의 category와 연관된 string pointer 반환(ex. locale name)
실패시 : NULL pointer 반환

query 함수로 활용
두번째 argument가 NULL pointer라면, 해당 category에 대한 현재 locale 정보를 string으로 반환한다.
LC_ALL도 적용가능하다.
반환값을 저장해뒀다가 나중에 setlocale을 호출할때 사용해도 된다.

Locales

locale은 컴파일러마다 다르다.
Linux에선 language[_territory][.codeset][@modifier] 형태의 추가 locale을 허용한다.
([]에 있는건 optional)
예를들어 en_GB.iso88591은 English - Unitedkingdom이면서 ISO/IEC 8859-1 character set을 사용하는 경우이다.

가능한 language는 ISO 639에, territory는 ISO 3166에 있다.
codeset은 character set이나 character set의 encoding을 나타낸다.

locale 정보의 중요성이 증가해 Uicode Consortium 에선 Common Locale Data Repository (CLDR)을 만들어 locale의 standard set을 만들고 있다.
https://cldr.unicode.org/

The localeconv Function

struct lconv *localeconv(void);

setlocale로도 현재 locale에 대한 정보를 가져올 수 있지만,
더 정확한 정보, 예를들면 "지금 decimal-point character는?" 같은, 를 가져오기 위해선 localeconv가 필요하다.

struct lconv pointer를 return한다.
struct lconv은 static storage duration인 structure이고,
이 structure의 member는 current locale에 대한 자세한 정보를 포함한다.

`lacaleconv`나 `setlocale`의 호출로 인해 값이 변경될 수 있으니 주의해야 한다.

해당 structure에 대한 자세한 설명은 p.664에 표시해둔 부분부터 참고..
http://www.cplusplus.com/reference/clocale/lconv/
이거 봐도 되고...


25.2 Multibyte Characters and Wide Characters

예전에 정확히 이해하지 못했던 부분이니까 최대한 자세히게 적어보자...

각 locale마다 다른 character set을 지원한다.
특히 asia 지역의 문자는 수천개를 넘어간다.(수천이뭐야 한자는 수만개지..)

char의 의미를 바꿔서 더 큰 character set을 지원해주는건 불가능하다.
왜냐하면 char은 single byte로 이미 정의됐기 때문이다.

대신, C는 compiler가 extended character set을 제공하도록 허용했다.
이 character set은 C program을 작성하거나, program이 작동되는 환경에서 쓰일 수 있다.

C는 이 extended character set을 encoding하는 두가지 방법을 제공하는데,
(1) multibyte character
(2) wide character
이다.

하나만 있으면 되는거 아닌가?
MB 방식은 I/O device에서 사용하기 좋고,
WC 방식은 프로그램 내에서 사용하기 좋다.
Q&A 참고

Multibyte Characters

extended character set을 encoding하는 방식 1

Multibyte character encoding에선 extended character는 1byte 이상으로 표현된다.
encoding하는데 사용되는 bytes의 개수는 character에 따라 다르다.
다만 특정 essential character(ex. letters, digits, white-space character 등)는 반드시 single byte로 표현돼야한다.
그 외 bytes(essentail character 외.. 를 말하는거겠지)는 multibyte character의 시작으로 해석될 수 있다.

몇몇 multibyte character set은 "state-dependent encoding"이다.
얘네의 각 character는 initial shift state로 시작하는데, 이걸 통해 몇 byte씩 읽을지 결정한다.
읽다가 만나는 shift sequence라는 byte가 그 뒤 byte를 몇 byte씩 읽을지 변경할 수 있다.
(ex. 일본의 JIS가 이런 방식이다. one-byte code와 two-byte code가 섞여있다.)
(Shift-JIS encoding은 state-dependent encoding이 아니다. 얘네도 1byte code와 2byte code가 섞여있긴한데, 2byte의 첫번째 byte와 1byte code와는 구분이 된다.)

모든 encoding에서 zero byte는 null character를 나타낸다. 그리고 multibyte character에서 두번째 byte는 zero byte일 수 없다.

MB_LEN_MAX(<milits.h>)는 지원되는 locale 의 multibyte 중 가장 긴 number of bytes를 저장하고,
MB_CUR_MAX(<stdlib.h>)는 현재 locale 의 multibyte 중 가장 긴 number of bytes를 저장한다.

모든 string은 multibyte character를 포함할 수 있다.
strlen에 의해 결정되는 길이는 character 수가 아니라 byte수이다.
format string도 multibyte character를 포함할 수 있다.
C99 standard에선 multibyte stringstring은 같은 말이다.

Wide Characters

extended character set을 encoding하는 방식 2

다양한 byte 수를 사용하는 multibyte character와는 다르게, wide character는 implementation에 따라 고정된 byte 수를 갖는다.

wide stringwide characters로 구성된 string이고, null wide character가 마지막에 온다
(null wide character == wide character whose numerical value is zero)

wide characterwchar_t type을 가진다.
wchar_t (<stddef.h> 등) 는 지원되는 locale 중 가장 큰 extended character set을 표현할 수 있는 integer type 이어야한다.
(ex. 2bytes로 충분하면 wchar_tunsigned short int로 정의 될 수 있다.)

L'a' : wide character constant
L"abc" : wide string literal
(L 안붙이면 그냥 multibyte 방식으로 인코딩하지 싶다.)

Unicode and the Universal Character Set

Unicode는 Unicode Consortium에서 1991년에 만든 방대한 character set이다.
(Unicode consortium : group of computer manufacturers가 compuer에서 사용하기 위한 international character set을 만들기 위해 설립한 기구)

Unicode에 처음 나오는 256개의 characters는 Latin-1과 같다.
(따라서 Unicode의 처음 128개 character는 ASCII character set과 같다.)
Unicode는 Latin-1을 넘어서서 거의 모든 현대와 고전 언어 문자를 포함한다.
심지어 수학이나 음악에서 쓰이는 다양한 symbols도 포함한다.

ISO는 ISO/IEC 10646 표준에서 Universal Character Set(USC)라는 character encodng을 정의했다.
이는 Unicode가 처음 정의될때쯤 시작했고, 둘은 처음엔 달랐지만, 나중에 두 character set은 통합됐다.

ISO는 Unicode Consortium과 협력하며 ISO/IEC 10646이 Unicode와 일관성을 유지하도록 하고 있다.

Unicode는 처음에 65,536(16bits로 표현 가능)개의 code로 제한돼있었는데,
부족하다는게 드러나서 현재는 100,000개의 characters를 넘어간다.
첫번재 65,536개의 characters는 Basic Multilingual Plane(BMP)라고 한다.

unicode 관련 article

Encodings of Unicode

Unicode는 각 character에 고유한 number를 부여했다. 이를 code point라 한다.
이 code point를 나타내는 방법(encoding 방식)은 여러가지가 있는데,
그 중 2가지 unicode encoding을 알아보자.

  1. UCS-2
    wide-character encoding 방식
    각 unicode code point는 2bytes로 저장된다.
    BMP를 모두 나타낼 수 있다.(그 이상은 안됨)

  2. 8-bit UCS Transformation Format(UTF-8)
    multibyte character encoding 방식
    고정된 byte를 사용하는 것이 아니라서, ASCII code와 같은 모양을 가진다는 장점이 있다. 처음 1byte는 ASCII와 구분이 안된다.
    UTF-8을 지원하는 software는 ASCII도 별도의 변환없이 읽을 수 있어서 이 방식은 널리 사용됐다.(webpage, email...)
    (Ken Thompson(B언어 만든 사람)과 Rob Pike가 1992년에 만들었다.)

UTF-8이 저장되는 매커니즘은 아래와 같다.

Code Point Range(16진수)UTF-8 Byte Sequence(Binary)
000000-00007F0xxxxxxx
000080-0007FF110xxxxx 10xxxxxx
000800-00FFFF1110xxxx 10xxxxxx 10xxxxxx
010000-10FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxx

이렇게 해당 범위의 code point는 x로 표시된 곳에 필요한 크기에 따라 나뉘어져서 들어간다.
byte 3개까지 이용하면 BMP 모두 표현할 수 있다.

각 byte마다 앞에 붙어있는 특정 수는 총 몇 byte인지를 알려주는 표시다.
ex. 110 : 2개 byte 이용한단 뜻이고, 10은 후속 byte임을 알려줌.
(위에서 말했던 Shift-JIS도 이런 방식을 사용하지 싶네)

이 특징은 각 sequnce of bytes 내에는 다른 의미를 가진 multibyte가 올 수 없단 뜻이고,
multibyte string 내에서 특정 단어를 검색할때 byte 비교만 해도 된단 뜻이다.

UTF-8은 모든 Unicode character를 표현할 수 있고, UCS-2보다 대게는 적은 공간을 차지한다. 또한 ASCII와의 compatibility도 가진다.
4bytes를 사용한 UCS-4도 있고,
UCS-2를 확장하고 multibyte encoding 특징을 추가한 UTF-16도 있다.

참고)
https://namu.wiki/w/UTF-8
https://ko.wikipedia.org/wiki/UTF-16

Multibyte/Wide-Character Conversion Functions

C89에 정의된 <stdlib.h>에 있는 함수 5개 중 character를 다루는 함수에 대해 알아보겠다.
C99에서 추가로 <wchar.h><wctype.h>에 multibyte와 wide character 관련 함수를 정의하고 있다.

MB를 WC로 변환하는 함수들은 현재 locale의 LC_CTYPE category의 영향을 받는다.

만약 MB encoding이 state-dependent라면, 현재의 conversion state에도 영향을 받는다.
conversion state는 현재 shift state와 현재 position으로 결정된다.

공통) 아래 세 함수의 char * parameter에 NULL pointer를 넣으면 함수의 internal conversion state는 initial conversion state로 세팅된다.
그리고 만약 multibyte encoding이 state-dependent라면 저렇게 NULL pointer를 넣었을때 nonzero를 반환하고, state-dependent가 아니라면 zero를 반환한다.
(즉, state dependent인지 아닌지 알 수 있음)

mblen

int mblen(const char *s, size_t n);

첫번째 parameter가 가리키는 bytes가 유효한 multibyte character인지 check한다.
valid multibyte character라면 해당 character의 number of bytes를 반환한다.
유효하지 않다면 -1을 반환한다.
null character면 0을 반환한다.

두번째 parameter는 check할 bytes 수를 제한하는데,
보통 MB_CUR_MAX를 사용한다.

사용예시)

//string의 모든 multibyte character가 유요하다면 0 반환
int mbcheck(const char *s) {
	int n;
    
    for (mblen(NULL, 0); ; s+=n)
    	if ((n = mblen(s, MB_CUR_MAX)) <= 0)
        	return 0;
}

for문에서 mblen(NULL, 0);이라고 한 이유는, 이 함수의 internal shift state를 initial shift state로 변경하기 위해서이다.
계속 검사하다가 마지막은 어차피 null character일 것이기 때문에(mbcheck는 string을 검사하는 중), 마지막까지 유요한 multibyte 였다면 mbcheck0을 반환할 것이다.

mbtowc

int mbtowc(wchar_t * restrict pwc, const char * restrict s, size_t n);

Multibyte character를 Wide character로 변환한다.

첫번째 parameter는 결과를 저장할 곳이다.
세번째 parameter는 이 함수가 시험할 길이를 제한한다.

반환값은 mblen과 같다.
(multibyte가 유요하다면 byte 수, 아니라면 -1, 두번째 argument가 null character이면 0)

wctomb

int wctomb(char *s, wchar_t wc);

wc를 mb로 변환한다.

첫번재 parameter에 저장이 되는데, 최대 MB_LEN_MAX까지 저장될 수 있다. 마지막에 null character는 추가하지 않는다.

반환값은 mb의 bytes 수이며, 유효한 mb와 일치하지 않는다면 -1을 반환한다.
null wide character가 두번째 인자로 들어오면 1을 반환한다.

Multibyte/Wide-String Conversion Functions

C89에 정의된 <stdlib.h>에 있는 함수 5개 중 string을 다루는 함수에 대해 알아보겠다.

MB string을 WC string으로 변환하는 함수들은 현재 locale의 LC_CTYPE category의 영향을 받는다.

mbstowcs

size_t mbstowcs(wchar_t * restrict pwcs, const char * restrict s, size_t n);

세번째 parameter는 첫번째 paramter의 배열에 저장된 wide character의 숫자이다.(배열이니까 길이 넘겨받는건 당연)

mbstowcs는 길이 제한에 도달하거나 null character를 만나면 멈춘다.

수정된 array elements의 개수를 반환한다.(null 제외)
invalid multibyte character와 만나면 -1반환한다.

wcstombs

size_t wcstombs(char * restrict s, const wchar_t * restrict pwcs, size_t n);

세번째 parameter는 첫번째 parameter인 array에 저장될 수 있는 bytes 수를 제한한다.

얘도 마찬가지로 세번째 parameter까지 가거나 null character를 만나면 멈춘다.
(null character는 저장)

저장된 array elements의 개수를 반환한다.(null 제외)
multibyte character와 매칭되지 않는 wide character를 만나면 -1반환한다.


25.3 Digraphs and Trigraphs

특정 지역의 programmer들은 C에 필요한 기호가 keyboard에 없어서 문제를 겪었다.
그래서 C89에서 이런 character를 표현할 수 있는 trigraph를 소개했다.

하지만 인기가 크게 없는 걸로 판별났고, Amendment 1에서 digraph(trigraph보다 readable)과 <iso646.h> header(특정 C operator 표현하는 macro 정의)를 추가했다.

Trigraphs

Trigraph SequenceASCII Equivalent
??=#
??([
??)]
??/\
??'^
??<{
??>}
??!|
??-~

ASCII code에 있는 것들 대신 자유롭게 사용할 수 있다.

ex)

??=include <stdio.h>

int main(void)
??<
	printf("Hello, world\n");
    return 0;
??>

??가 string literal 내에서 쓰일때 compiler가 trigraph로 알아보고 오류가 생길 수 있다.
?\? 따라서 이렇게 escape sequence를 같이 사용해주면 좋다.

Digraphs

DigraphToken
<:[
:>]
<%{
%>}
%:#
%:%:##

얘는 trigraph와 다르게 token substitute이다.
따라서 string literal이나 character constant내에서 인식될 일이 없다.

The <iso646.h> Header

Alternative Spellings
C의 몇몇 operator를 macro로 정의한다.

MacroValue
and&&
and_eq&=
bitand&
bitor`
compl~
not!
not_eq!=
or||
or_eq|=
xor^
xor_eq^=

25.4 Universal Character Names (C99)

Universal Character Names(UCS)을 사용해 UCS가 source code 내에서 쓰일 수 있게 해준다.

escape sequence와 닮았지만 차이가 있는데, 바로 string이나 character가 아니라 code내에서도 사용할 수 있다는 점이다.
idnetifier에도 쓰일 수 있어서 함수이름 같은걸 programmer들의 native language로 작성할 수 있다.

Universal Character Name을 작성하는 방법
(d는 hexadecimal digit)

  1. \udddd
  2. \Udddddddd

해당 code 번호에 맞는 번호를 위 두가지 방식 중 하나로 작성할 수 있다.
1번으로 BPM을 모두 표현할 수 있고, 나머지는 2번 방식을 사용해야 한다.
UCS의 code point는
https://www.unicode.org/charts/
에 있다. (Unicode와 동일)

주의)
모든 Universal Character Name이 identifier로 사용될 수 있는 건 아니다. C99에 허용된 애들이 명시돼있다.
그리고 identifier에서 사용할때 숫자를 나타내는 UCN은 제일 앞에 올 수 없다.

또 얘네는 ascii같은 universal "code"가 아님에 주의하자. 즉, unicode에선 character와 code point가 매칭될 뿐이고, 얘네는 그런 code point를 해당 character를 나타내는데 사용할 뿐이다.
컴퓨터에 어떻게 저장되는지는 encoding 방식에 따라 다르다. unicode도 여러 encoding 방식이 있듯이, code point가 ASCII처럼 그대로 저장된다고 생각하면 안된다.


25.5 The <wchar.h> Header (c99)

Extended Multibyte and Wide-Character Utilities

<wchar.h>wide-character의 input/outputwide string manipulation을 다루는 함수를 제공한다.
(<stdio.h><string.h>의 wide-character version인 경우가 많다.)

말했듯이, wide-character를 다루는 함수만 제공한다. 왜냐하면 C의 기본 함수는 모두 multibyte character를 다룰 수 있기 때문에 특별한 함수가 필요없다. 예를들어 fpritnf는 multibyte character가 포함된 format string을 다룰 수 있다.

Q. 왜 multibyte character는 다룰 수 있지? wide는 안되면서?
A. 안 알려줬을 뿐이지, 원래부터 ASCII만이 아니라 multibyte character 지원한거지.
wide character는 당연히 안되는게, 단위를 2bytes 3bytes 잡아버리면, 호환이 안됨.

getc 같은 byte(char) 단위로 읽는 애들도 mb랑 완벽하게 호환되진 않는다.

C의 default encoding은?
링크보면 알겠지만, C는 locale이나 implementation따라 정해지는 것 같다.
이미 encoding 방식이 정해져있으니 일반적인 함수들은 그에따라 encoding하며 사용되는거지. 그동안 ASCII라고 세뇌당해서 어색하게 느껴지는듯

<wchar.h> types, macro

(이 외에도 더 있음)

  • mbstate_t : 이 type의 value를 mb와 wc가 서로 변환될때 conversion state를 저장하는데 사용한다.
  • wint_t : extended characters를 나타내는데 사용하는 integer type
  • WEOF : wint_t로 나타내는 값 중 다른 extended character와 다른 값이다. EOF처럼 오류나 end-of-file 조건을 나타내는데 사용한다.

wchar_twint_t 차이??
https://stackoverflow.com/questions/1081456/wchar-t-vs-wint-t
첫번째 답변에 musiphil comment 참고

여기 대부분 함수들은 비슷한 함수의 argument나 return type이 wide-character로 바뀐 것 밖에 없다.
예를들어 charwchar_t로, bytes세는 함수는 wide-character 개수 세는 걸로 등...

Stream Orientation

C89엔 없던 개념이다. wide character 관련 함수들 이해하려면 숙지해야하는 개념이다.

모든 stream은 byte-oriented(traditional orientation)이거나 wide-oriented(data is written to the stream as wide characters)이다.

Stream이 처음 열리면 orientation은 없다.
byte input/output operation을 수행하면 byte-oriented가 되고,
wide-character input/output을 수행하면 wide-oriented가 된다.
혹은 fwide 함수를 통해서 orientation을 고를 수 있다.

열려있는 동안 orientation을 유지하고,
freopen을 통해 reopen되면 stream은 orientaton을 삭제한다.

wide-oriented stream에선,
wide character를 file에 작성하면 저장될때 multibyte character로 바뀌고, 읽어올때는 반대로 한다.

file에 사용되는 multibyte encoding은 program 내에서 쓰인 것과 비슷하다.
(file에선 embedded null bytes를 포함할 수도 있단 것 말고는..)

각각의 wide-oriented stream은 mbstate_t object와 연관돼서 stream의 conversion state를 keep track.

만약 wc가 mb로 전환되거나 mb에서 전환하는데, valid multibyte character가 아니라면 errnoEILSEQ를 저장한다.

제한)
stream이 byte-oriented가 되면 wide-character input/output 함수를 적용하는건 illegal이고,
마찬가지로 wide-oriented에 byte input/output 함수를 적용하는 것도 illegal이다.
다른 함수들은 어디에도 적용될 수 있다.

실제로 printf하고 wprintf해보니 적용이 안됨

추가로,
1) Binary wide-oriented stream은 file-positioning restriction에 해당된다.(text, binary stream 둘 다)
2) wide-oriented stream에 file-positioning operation을 하게되면, multibyte character의 한 부분을 overwrite 할 수 있다. 남은 부분이 indeterminate state가 된다.
3) wide-oriented stream에서 fgetpos를 호출해 fpos_t를 반환받으면, fpos_t에는 mbstate_t object도 포함돼있다. 따라서 fpos_t를 다시 fsetpos에 넘기면 mbstate_t도 같이 넘어가서 그 값을 되찾는다.


따로 또 정리해보자면,

byte-oriented는 multibyte character(mb)를 mb로 저장한다.
wide character(wc)는 애초에 byte-oriented의 함수가 건들 수 없으니 고려 X
wc들은 전용 함수가 있다.
multibyte는 기존 함수로 control 할 수 있다
(getchar 같은 byte 단위로 읽는 것은 주의..)

그리고 wide-oriented는 wc를 mb로 저장하고, 읽어올때는 mb를 wc로 변환한다.
mb를 저장하는건 애초에 고려할 필요가 없다.
wchar_t를 인자로 받으니, mb가 들어올 일이 없다.

전반적인 이해 돕기 위한 글)
https://www.gnu.org/software/libc/manual/html_node/Extended-Char-Intro.html

wide-oriented에서 잘 변환/저장하려면 locale이 잘 설정돼있어야한다.
stdlib의 mb <-> wc 전환하는 함수들은 LC_CTYPE category의 영향을 받는다.
근데 wide-oriented에서 wc를 mb로 저장하기 위해선 변환을 먼저해야되니
위 함수(ex. wctomb)가 개입한다고 하는데..(인터넷 카더라)
locale을 제대로 설정해줘야 잘 변환되더라.
기본 C locale("C")에선 ascii밖에 인정이 안된다고 한다.
따라서 setlocale(LC_ALL,""); 이라도 해줘야 변환이 잘된다.(아래 링크1 채택답변 참고)

근데 여기서 의문인게..
mb가 locale-dependet인데(아래 링크2 답변 참고)
왜 mb는 기본 locale이어도 잘 저장되고 wc는 기본이면 변환을 이유로 잘 저장이 안되는거지?
mb를 mb 그대로 저장할때는 괜찮은데,
wc에서 mb로 변환될때만 locale이 문제가 된다는게 의문이다.
정확히 locale이 어떻게 어떤 영향을 주는지 잘 모르겠으나, 일단 위 문단 내용대로만 알고 있자.

링크1) https://stackoverflow.com/questions/10965213/why-the-wide-character-woes
링크2) https://stackoverflow.com/questions/59521032/is-there-any-locale-that-affects-wide-character-encoding


<wchar.h>의 함수들

  1. Formatted Wide-Character Input/Output Functions

  2. Wide-Chracter Input/Output Functions

  3. General Wide-String Utilities

  4. Wide-String
    Copying/Concatenation/Comparison/Search/Time
    Conversion Functions

  5. Single-Byte/Wide-Character Conversion Functions

  6. Restartable Multibyte/Wide-Chracter Conversion Functions

  7. Restartable Multibyte/Wide-String Conversion Functions

이렇게 많은 목록들이 있다. 대~~부분 counterpart인 multibyte버전의 함수가 있고 비슷하게 작동하며, 차이는 책에 잘 기술돼있다.
이걸 전부 다 또 정리하고 그렇고.. 뭔가 할거 아니면 딱히 쓸일도 당장은 크게 없을 것 같아서 필요하면 책 찾아보며 사용하는걸로 일단 하자.

counterpart 없이 새로 등장한 5,6,7번 목록의 함수들(+4번의 Time conversion)도 필요할때 찾아보자..
아직은 필요성도 크게 못느끼겠고...

math 함수들이랑 <wchar.h> 함수들은 필요할때 찾아보는걸로...

fwide

얘만 좀 정리해보자면

int fwide(FILE *stream, int mode);

stream의 현재 orientation을 set하려고 시도한다.

두번째 인자(mode)

  • mode > 0 : no orientation이라면 stream을 wide-orientation으로 만들려고 시도한다.
  • mode < 0 : no orientation이라면 stream을 byte-orientation으로 만들려고 시도한다.
  • mode = 0 : orientation 변경 X

만약 stream의 orientation이 이미 있다면 변경되지 않는다.

Return valuefunction call 이후에 orientation을 기준으로 한다.
wide orientation이면, positive
byte orientation이면, negative
no orientation이면, zero
를 반환한다.


25.6 The <wctype.h> Header (C99)

Wide-Character Classification and Mapping Utilities

<ctype.h>의 wide-character 버전이다.
이 헤더의 함수들은 current locale의 LC_CTYPE category의 영향을 받는다.

Types & macro

아래의 typesmacro를 정의한다.

  • wint_t : <wchar.h>에도 정의돼있음
  • wctype_t : locale-specific character classification 값을 나타내는 type
  • wctrans_t : locale-specific character mapping 값을 나타내는 type
  • WEOF : <wchar.h>에도 정의돼있음

Functions

Functions<ctype.h>와 마찬가지로
1. character-classification functions
2. case-mapping functions
를 제공하며,
3. extensible functions
도 추가로 제공한다.

1.character-classification functions & 2.case-mapping functions

1번과 2번 함수는 <ctype.h>의 상대와 거의 일치하게 행동한다.
자세한 함수 list는 책 참고

차이가 있다면,
1번 함수에서 space를 제외한 white-space wide character는 printing character이다.(<ctype.h>에선 아님)
2번 함수에선 이상한 결과가 나올 수 있는데, 하나의 문자의 lower case가 1개 이상일 수 있기 때문이다.
(영어는 'A', 'a' 짝이 맞는데 안그런 언어도 있을 수 있으니까)

3.extensible functions

3번 함수인
Extensible Wide-Character Classification Functions 2개,
Extensible Wide-Character Mapping Functions 2개,
얘네는 각각 2개가 한번에 같이 쓰인다.
standard에서 제공하는 위의 함수들 말고 implementation에서 추가로 지원하는 기능을 사용하기위해 쓴다.

Classification 함수를 예로 들자면,
wctype에 원하는 condition을 넣으면(ex.digit), 그걸 표현하는 class(OOP class아님..)가 wctype_t로 return된다.
그럼 그 값을 iswctype에 원하는 wide character와 함께 넣으면 판별이 되는 것이다.
즉, iswctype(wc, wctype("alnum"));iswalnum(wc);와 같다.
그래서 이런 standard의 함수를 거의 그대로 쓰는 경우 말고, implementation이 추가로 지원하는 classification 기능을 사용하기위해 쓴다.
mapping도 마찬가지..


Q&A

setlocale이 반환하는 string의 길이는? 이걸 어떻게 저장하지?
길이는 딱히 제한된게 없다.
따라서 dynamic allocate를 해야한다.
일단은 char *에 assign한 뒤(string literal 같은 static storage duration 반환하나봄.),
해당 길이만큼 malloc으로 배열 만들어서 저장해주면 된다.

왜 encoding 방식이 multibyte랑 wide character 두개나 있지?
Multibyte는 input/output에서 사용하기 좋다. I/O device는 주로 byte-oriented이기 때문이다.
Wide character는 프로그램 내에서 사용하기 좋은데, 모든 wide character가 같은 크기의 공간을 차지하기 때문이다.
따라서 프로그램 내에선 WC, 밖에선 MB를 주로 사용한다.
(서로 변환되며...)(물론 이건 "주로 그런다"는거임)

위에도 있지만..
https://www.gnu.org/software/libc/manual/html_node/Extended-Char-Intro.html
이거 참고해보면 좋음

Unicode랑 UCS랑 차이가 뭐임?
같은 character와 각각의 character에 같은 code point를 사용한다.
하지만 Unicode는 그저 character set의 역할만 하는게 아니다.
예를들면 bidirectional display order를 지원한다. 아랍어 같은 경우 왼쪽이 아니라 오른쪽부터 쓰는데, 이를 지원해주는 것이다.

0개의 댓글