C를 international 하게 만들기 위해 다양한 언어를 지원해야 됐었고, 1994년에 이런 특징을 좀 포함한 Amendment 1 이 승인됐다. 그리고 C99에서 international features이 더 추가됐다.
<locale.h>
HeaderLocalization
이 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 : 달을 먼저 적기도하고, 날짜를 먼저 적기도 한다.
locale을 변경할때, library의 모든 parts를 다 변경할 필요는 없다.
이를 위해 category인 아래 macro를 사용할 수 있다.
LC_COLLATE
: strcoll
과 strxfrm
에 영향 (<string.h>
)
LC_CTYPE
: <ctype.h>
의 함수들(isdigit
, isxdigit
제외)에 영향
multibyte와 wide-character functions에도 영향
LC_MONETARY
: localeconv
함수로부터 반환된 monetary formatting information에 영향
LC_NUMERIC
: formatted I/O에 쓰인 decimal-point character에 영향
numeric conversion functions (ex. stdtod
)에 영향(in <stdlib.h>
)
localeconv
함수로부터 반환된 monetary formatting information에 영향
LC_TIME
: time을 character string으로 바꾸는 strftime
함수(<time.h>
)에 영향
wcsftime
함수에 영향
Implementationdl LC_
macro를 추가로 정의해도 된다.
setlocale
Functionchar *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
을 호출할때 사용해도 된다.
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/
localeconv
Functionstruct 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/
이거 봐도 되고...
예전에 정확히 이해하지 못했던 부분이니까 최대한 자세히게 적어보자...
각 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 참고
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 string과 string은 같은 말이다.
extended character set을 encoding하는 방식 2
다양한 byte 수를 사용하는 multibyte character와는 다르게, wide character는 implementation에 따라 고정된 byte 수를 갖는다.
wide string은 wide characters로 구성된 string이고, null wide character가 마지막에 온다
(null wide character == wide character whose numerical value is zero)
wide character는 wchar_t
type을 가진다.
wchar_t
(<stddef.h>
등) 는 지원되는 locale 중 가장 큰 extended character set을 표현할 수 있는 integer type 이어야한다.
(ex. 2bytes로 충분하면 wchar_t
는 unsigned short int
로 정의 될 수 있다.)
L'a'
: wide character constant
L"abc"
: wide string literal
(L
안붙이면 그냥 multibyte 방식으로 인코딩하지 싶다.)
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는 각 character에 고유한 number를 부여했다. 이를 code point라 한다.
이 code point를 나타내는 방법(encoding 방식)은 여러가지가 있는데,
그 중 2가지 unicode encoding을 알아보자.
UCS-2
wide-character encoding 방식
각 unicode code point는 2bytes로 저장된다.
BMP를 모두 나타낼 수 있다.(그 이상은 안됨)
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-00007F | 0xxxxxxx |
000080-0007FF | 110xxxxx 10xxxxxx |
000800-00FFFF | 1110xxxx 10xxxxxx 10xxxxxx |
010000-10FFFF | 11110xxx 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
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인지 아닌지 알 수 있음)
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 였다면 mbcheck
는0
을 반환할 것이다.
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)
int wctomb(char *s, wchar_t wc);
wc를 mb로 변환한다.
첫번재 parameter에 저장이 되는데, 최대 MB_LEN_MAX
까지 저장될 수 있다. 마지막에 null character는 추가하지 않는다.
반환값은 mb의 bytes 수이며, 유효한 mb와 일치하지 않는다면 -1
을 반환한다.
null wide character가 두번째 인자로 들어오면 1을 반환한다.
C89에 정의된 <stdlib.h>
에 있는 함수 5개 중 string을 다루는 함수에 대해 알아보겠다.
MB string을 WC string으로 변환하는 함수들은 현재 locale의 LC_CTYPE
category의 영향을 받는다.
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
을 반환한다.
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
을 반환한다.
특정 지역의 programmer들은 C에 필요한 기호가 keyboard에 없어서 문제를 겪었다.
그래서 C89에서 이런 character를 표현할 수 있는 trigraph를 소개했다.
하지만 인기가 크게 없는 걸로 판별났고, Amendment 1에서 digraph(trigraph보다 readable)과 <iso646.h> header
(특정 C operator 표현하는 macro 정의)를 추가했다.
Trigraph Sequence | ASCII Equivalent |
---|---|
??= | # |
??( | [ |
??) | ] |
??/ | \ |
??' | ^ |
??< | { |
??> | } |
??! | | |
??- | ~ |
ASCII code에 있는 것들 대신 자유롭게 사용할 수 있다.
ex)
??=include <stdio.h>
int main(void)
??<
printf("Hello, world\n");
return 0;
??>
??
가 string literal 내에서 쓰일때 compiler가 trigraph로 알아보고 오류가 생길 수 있다.
?\?
따라서 이렇게 escape sequence를 같이 사용해주면 좋다.
Digraph | Token |
---|---|
<: | [ |
:> | ] |
<% | { |
%> | } |
%: | # |
%:%: | ## |
얘는 trigraph와 다르게 token substitute이다.
따라서 string literal이나 character constant내에서 인식될 일이 없다.
<iso646.h>
HeaderAlternative Spellings
C의 몇몇 operator를 macro로 정의한다.
Macro | Value |
---|---|
and | && |
and_eq | &= |
bitand | & |
bitor | ` |
compl | ~ |
not | ! |
not_eq | != |
or | || |
or_eq | |= |
xor | ^ |
xor_eq | ^= |
Universal Character Names(UCS)을 사용해 UCS가 source code 내에서 쓰일 수 있게 해준다.
escape sequence와 닮았지만 차이가 있는데, 바로 string이나 character가 아니라 code내에서도 사용할 수 있다는 점이다.
idnetifier에도 쓰일 수 있어서 함수이름 같은걸 programmer들의 native language로 작성할 수 있다.
Universal Character Name을 작성하는 방법
(d
는 hexadecimal digit)
\udddd
\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처럼 그대로 저장된다고 생각하면 안된다.
<wchar.h>
Header (c99)Extended Multibyte and Wide-Character Utilities
<wchar.h>
는 wide-character의 input/output과 wide 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 typeWEOF
: wint_t
로 나타내는 값 중 다른 extended character와 다른 값이다. EOF
처럼 오류나 end-of-file 조건을 나타내는데 사용한다.wchar_t
랑 wint_t
차이??
https://stackoverflow.com/questions/1081456/wchar-t-vs-wint-t
첫번째 답변에 musiphil comment 참고
여기 대부분 함수들은 비슷한 함수의 argument나 return type이 wide-character로 바뀐 것 밖에 없다.
예를들어 char
가 wchar_t
로, bytes세는 함수는 wide-character 개수 세는 걸로 등...
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가 아니라면 errno
에 EILSEQ
를 저장한다.
제한)
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>
의 함수들Formatted Wide-Character Input/Output Functions
Wide-Chracter Input/Output Functions
General Wide-String Utilities
Wide-String
Copying/Concatenation/Comparison/Search/Time
Conversion Functions
Single-Byte/Wide-Character Conversion Functions
Restartable Multibyte/Wide-Chracter Conversion Functions
Restartable Multibyte/Wide-String Conversion Functions
이렇게 많은 목록들이 있다. 대~~부분 counterpart인 multibyte버전의 함수가 있고 비슷하게 작동하며, 차이는 책에 잘 기술돼있다.
이걸 전부 다 또 정리하고 그렇고.. 뭔가 할거 아니면 딱히 쓸일도 당장은 크게 없을 것 같아서 필요하면 책 찾아보며 사용하는걸로 일단 하자.
counterpart 없이 새로 등장한 5,6,7번 목록의 함수들(+4번의 Time conversion)도 필요할때 찾아보자..
아직은 필요성도 크게 못느끼겠고...
math 함수들이랑 <wchar.h> 함수들은 필요할때 찾아보는걸로...
얘만 좀 정리해보자면
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 value는 function call 이후에 orientation을 기준으로 한다.
wide orientation이면, positive
byte orientation이면, negative
no orientation이면, zero
를 반환한다.
<wctype.h>
Header (C99)Wide-Character Classification and Mapping Utilities
<ctype.h>
의 wide-character 버전이다.
이 헤더의 함수들은 current locale의 LC_CTYPE
category의 영향을 받는다.
아래의 types와 macro를 정의한다.
wint_t
: <wchar.h>
에도 정의돼있음wctype_t
: locale-specific character classification 값을 나타내는 typewctrans_t
: locale-specific character mapping 값을 나타내는 typeWEOF
: <wchar.h>
에도 정의돼있음Functions은 <ctype.h>
와 마찬가지로
1. character-classification functions
2. case-mapping functions
를 제공하며,
3. extensible functions
도 추가로 제공한다.
1번과 2번 함수는 <ctype.h>
의 상대와 거의 일치하게 행동한다.
자세한 함수 list는 책 참고
차이가 있다면,
1번 함수에서 space를 제외한 white-space wide character는 printing character이다.(<ctype.h>
에선 아님)
2번 함수에선 이상한 결과가 나올 수 있는데, 하나의 문자의 lower case가 1개 이상일 수 있기 때문이다.
(영어는 'A', 'a' 짝이 맞는데 안그런 언어도 있을 수 있으니까)
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도 마찬가지..
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를 지원한다. 아랍어 같은 경우 왼쪽이 아니라 오른쪽부터 쓰는데, 이를 지원해주는 것이다.