(C) 한글 문자열 상수 문제

gelddu의 이미지

아주 기본적인 질문 같은데요...
Windows7, Visual studio 2010에서
C로 다음과 같은 코드를 만들었을 때 빨간줄(syntax 오류)이 생깁니다..

char str[3] = "가";

오류 메시지: "const char[4]" 형식의 값을 사용하여 "char [3]" 형식의 엔터티를 초기화할 수 없습니다.

한글 한 글자가 2바이트이고 따라서 배열 크기를 3으로 하면 되는거 아닌가요?
그런데 왜 "가"라는 문자열 상수가 4바이트라고 나오는건가요?
sizeof("가")를 출력해봐도 3이 나오는데요.

akayong의 이미지

캐릭터셋이 뭐로 되어 있나요?

https://kldp.org/node/120815

이글 참고 하시면 도움이 될지도..

gelddu의 이미지

캐릭터셋의 문제라면
sizeof("가") 도 4가 나와야 하는거 아닌가요?

라스코니의 이미지

visual studio C++ 2015 community edition에서 잘 실행됩니다.
이상하네요.

chanik의 이미지

sizeof("가") 가 들어있는 소스파일의 인코딩과
char str[3] = "가"; 가 들어있는 소스파일의 인코딩이 서로 다를 것 같군요.
전자는 euc-kr인 것 같고, 후자는 utf-8일 것 같습니다.

소스파일 인코딩을 명확히 확인하고 실험해보시면 일관적인 결과가 나올 것입니다.

------

이미 다른 댓글들에 충분한 설명이 되어 있는 것 같긴 하지만,
파이썬3에서 아래와 같이 해 보면 인코딩 방식에 따라 '가' 자가 가질 수 있는
다양한 바이트열의 실체를 쉽게 확인해볼 수 있습니다.

>>> '가'.encode('utf-8')
b'\xea\xb0\x80'
>>> '가'.encode('euc-kr')
b'\xb0\xa1'

윈도우 메모장에서 유니코드로 저장하면 엔디안 별로 아래와 같이 표현됩니다.

>>> '가'.encode('utf-16be')
b'\xac\x00'
>>> '가'.encode('utf-16le')
b'\x00\xac'

dkim의 이미지

문자 <가>는 EUC-KR 혹은 CP949 인코딩 하에서는 2 바이트를 차지합니다만, 다른 인코딩에서는 그 길이가 다를 수 있습니다. 예를 들어, UTF-8 인코딩의 경우 3 바이트(EA B0 80)로 인코딩합니다.

C 문자열 상수는 원래 문자열 내용 외에 그 끝에 NULL 문자 '\0'가 따라옵니다. C 문자열 상수는 문자 배열 타입(char[N])을 가집니다. 그런데, C에서는 함수 인자로 배열을 넘겨주면 실제로는 그 배열의 첫 번째 원소에 대한 포인터만 전달됩니다. 즉, 배열 크기 정보가 사라집니다. 따라서, 호출된 함수 안에서도 문자열의 끝을 알 수 있도록 문자열 끝에 '\0' 문자를 포함시키도록 하고 있습니다.

따라서, 보여주신 코드에서 문자 <가>가 3 바이트로 인코딩되었다면, C 문자열 상수 "가"'\0'를 위한 공간을 포함한 4 바이트의 공간이 필요하며 배열 str의 크기 역시 4 (혹은 그 이상)이어야 합니다.

sizeof("가")sizeof(str)의 결과가 다르게 나온다는 실험 코드를 보여주실 수 있으신지요? 제가 VC++ 2015으로 실험해 본 바로는 기대한 대로 두 결과가 같았습니다: ​http://rextester.com/KRE16209

Anti-Lock의 이미지

저 역시 원 질문자님께서 실험코드를 보여야 할 것으로 생각합니다.

qiiiiiiiip의 이미지

궁금해서 vs 2010에서 해봤는데 동일한 증상이었습니다.

encoding은 cp949 인 상황에서
char str[3] = "가"; -> 오류표시
sizeof("가") = 3

오류표시가 나지만 컴파일은 잘 됩니다. (str[2] = "가"; 로 하면 error C2117: 'str' : 배열 범위 오버플로입니다. )
단순히 화면에 실시간으로 오류를 출력하는 파서의 문제가 아닐까 싶네요.

vs 2013 에서는 그런 증상 없습니다.

chanik의 이미지

구버전인 vc2008에서도 그런 증상 없이 잘 되네요.
2010에서만 나타나는 문제인 모양이네요.

-----

#include <iostream>
using namespace std;
 
char str[3] = "가";
 
int main()
{
	cout << str << endl;
	cout << "sizeof(\"\") : " << sizeof("가") << endl;
	return 0;
}

utf-8로 저장하면 아래와 같은 컴파일 오류가 생기고, 실행파일도 안 만들어집니다.

test.cpp(4) : error C2117: 'str' : 배열 범위 오버플로입니다.
        test.cpp(4) : 'str' 선언을 참조하십시오.

euc-kr로 저장하면 깨끗이 빌드되고 아래와 같이 나옵니다.

D:\test> test.exe
가
sizeof("가") : 3
qiiiiiiiip의 이미지


현재 원글자의 질문은 컴파일 타임에서의 오류가 아니라,

에디터에서 에러를 표시한다는 것이고요.

해당 기능은 vs2010부터 추가되었다고 합니다.

즉 vs 2008에서는 에디터에서 에러(로 추정되는 부분)에 빨간줄을 그어주지 않으므로, 당연히 원글자의 증상이 없겠습니다.

어차피 컴파일하기 전에 간단히 문법 오류 정도 체크할테니 오류가 있는 것도 별로 이상한 것 같지는 않습니다.

This is a new feature in VS2010: C++ IntelliSense can now display compiler-quality syntax and semantic errors as you browse and edit your code.

https://social.msdn.microsoft.com/Forums/vstudio/en-US/b3607baa-80ea-4467-8af2-701255539f2e/visual-studio-2008-doesnt-underline-errors-in-code?forum=vcgeneral

chanik의 이미지

질문을 다시 읽어보니 말씀하신대로 IDE 편집기에서 미리 보여주는 오류에 대한 것이군요.
저는 컴파일오류를 생각하며 VS 2008 명령프롬프트에서 테스트했습니다.
덕분에 머리속이 정리되는 느낌입니다.

익명 사용자의 이미지

"가"를 대입하지 마시고 "가"에 해당하는 숫자로된 코드값을 대입하세요.

익명 사용자의 이미지

이어서 cp949, euc-kr은 구닥다리 코드셋입니다.
C언어에서는
"가"에 해당하는 유니코드 값 0xac00 을 uint16, 또는 uint32 변수에 넣고 필요에 따라 utf-8, euc-kr, cp949 등의 코드로 변환 후에 출력하는 것이 바람직한 방법입니다.

sdjskr의 이미지

CP949 던 유니코드던 한글은 한 문자당 2 바이트 이상(UTF-8는 3 바이트, UTF-16는 2 바이트)인데 개당 1바이트인 char 배열에 넣는 것 자체가 이미 잘못된 거죠. 결과 값 또한 아무런 의미가 없습니다.

애초에 질문이 잘 못 된겁니다.

예는 첨부 파일 참조

댓글 첨부 파일: 
첨부파일 크기
Image icon hangul.png16.11 KB
익명 사용자의 이미지

multibyte character vs. wide character

익명 사용자의 이미지

현실에서 수십년동안 사용하던 방법입니다.

더 나은 방법이 나왔다고해서 잘못되었거나 의미가 없거나 하지 않습니다.

sdjskr의 이미지

char[] 에 leading byte와 tail byte로 구성시켜 한글을 집어 넣는 방식은 1바이트의 가격이 매우 비싸던 시절 어쩔 수 없이 어거지로 하던 방식이며, 이 경우 영어와 한글이 섞어 있을 경우 스트링 처리할 때, 어느것은 1 바이트 어느 것은 2 바이트이기 때문에 word counting의 경우 추가 알고리즘 구성해야 하며 이로인해 쓸데 없는 시간 낭비와 비용이 소요됩니다. 또한 문자가 많으면 많을 수록 성능 문제 또한 무시할 수 없습니다. 분명히 잘못된 방식이며 현재처럼 메모리가 싼 시점에서는 이제껏 그렇게 사용했다 하더라고 굳이 그렇게 쓸 필요가 없습니다.

익명 사용자의 이미지

network cost

익명 사용자의 이미지

wchar_t는 컴파일러 의존적이라 이식성이 좋지 않습니다. GCC에서는 기본적으로 4바이트인 반면, VC++ 하에서는 2바이트로 그 크기가 다릅니다.

더욱이 1996년에 발표된 유니코드 2.0부터는 코드 포인트의 수가 2^16보다 크고, 2003년에 발표된 유니코드 4.0 이후부터는 실제 포함된 문자의 수도 2^16을 넘어섰습니다. 즉, VC++에서는 문자 하나당 wchar_t 하나라는 것도 성립하지 않습니다. 즉, wchar_t를 쓰더라도 단순히 배열의 크기만으로 문자열에 포함된 문자의 수를 알 수 없으며 추가적인 알고리즘이 필요합니다.

또한, 멀티 바이트 인코딩인 UTF-8를 고정된 크기를 사용하는 UTF-32보다 압도적으로 많이 사용하고 있기 때문에, 파일이나 네트웍으로부터 처음으로 외부 자료를 처음 읽는 순간에는 멀티 바이트 인코딩을 피할 수 없습니다. C++ 표준은 그런 UTF-8 인코딩된 문자열을 char[]에 저장하도록 유도하고 있습니다:

http://en.cppreference.com/w/cpp/language/types

char - ... Multibyte characters strings use this type to represent code units. The character types are large enough to represent 256 different values (in order to be suitable for storing UTF-8 encoded data) (since C++14)

결론적으로, 멀티 바이트 문자열을 char[] 배열에 넣는 방식은 현재도 찡그릴 게 아니라고 생각합니다. 그리고, 다국어 지원을 제대로 하려면 C/C++ 언어와 표준 라이브러리만으로는 힘들고, ICU (http://site.icu-project.org/)와 같은 외부 라이브러리를 사용을 피할 수 없다고 합니다. 사실 유니코드가 C보다 나중에 만들어진 걸 고려하면, 기존 C에 포함된 개념만으로 유니코드 더 나아가 제대로 다국어 지원하기 어려운 건 당연한 듯합니다.

익명 사용자의 이미지

논점이 빗나가는 것 같은데 질문자의 질문을 다시 적겠습니다.
-----------------------------
아주 기본적인 질문 같은데요...
Windows7, Visual studio 2010에서
C로 다음과 같은 코드를 만들었을 때 빨간줄(syntax 오류)이 생깁니다..

char str[3] = "가";

오류 메시지: "const char[4]" 형식의 값을 사용하여 "char [3]" 형식의 엔터티를 초기화할 수 없습니다.

한글 한 글자가 2바이트이고 따라서 배열 크기를 3으로 하면 되는거 아닌가요?
그런데 왜 "가"라는 문자열 상수가 4바이트라고 나오는건가요?
sizeof("가")를 출력해봐도 3이 나오는데요.
---------------------------------

질문자는 C 언어로 만들었다고 합니다.
char str[3] = "가"; 이렇게 할당하는 것은 제가 보이에는 좀 이상합니다.
"가" 가는 글자를 파일로 저장하면 파일에는 당연히 멀티 바이트로 저장이 되는데 환경에 따라 저장되어 있는 값이나 길이가 다릅니다.
예를 들면 에디터로 utf-8 로 저장하고 프로그램 실행하여 출력하면 출력 콘솔 환경이 utf-8 이면 의도한대로 출력이 되는데,
만약 출력 콘솔 환경이 cp949 라면 이상한 문자들이 출력될 것입니다.
utf-8 로 저장하고 utf-8 환경의 콘솔에서 출력하면 문제가 발생되지 않을 것이나, 이러한 방법보다는
유니코드 관련 라이브러리를 사용하시는 것이 편리합니다.
유니코드 관련 라이브러리를 사용하지 않으신다면 유니코드를 직접 처리해야 하는데,
"가" 코드는 0xac00 이므로 uint16 또는 uint32 변수에 저장하면 됩니다.
출력할 때는
char *unichar_to_utf8(uint32 ch); 이런 함수를 구현하시거나 ...
말로 설명하면 길어지므로...

https://developer.gnome.org/glib/stable/glib-Unicode-Manipulation.html

유니코드 처리 API 를 참고하시기 바랍니다.
glib 라이브러리는 C 라이브러리이며 관련 소스가 공개되어 있으므로,
궁금한 부분의 함수 소스 코드를 읽어보시면 되겠습니다.
https://github.com/GNOME/glib
MS 플랫폼에서 유니코드를 처리할 수 있는 라이브러리가 있을 것 같습니다. 그걸 사용하시면 되겠습니다.
https://en.wikipedia.org/wiki/GLib 는 MS 플랫폼에서도 작동할 수 있습니다.

그리고 어떤 분은 네트워크 전송을 말씀하셨던데,
0xac00 을 utf-8 로 인코딩하면 char * 바이트코드(또는 uint8 *) 가 나오는데.. 그걸 네트워크로 전송하시면 되겠습니다.
머리아프게 생각할 필요가 없습니다. 유니코드가 나온지가 10년이 넘었습니다.

익명 사용자의 이미지

"CP949 던 유니코드던 한글은 한 문자당 2 바이트 이상(UTF-8는 3 바이트, UTF-16는 2 바이트)인데 개당 1바이트인 char 배열에 넣는 것 자체가 이미 잘못된 거죠." (sdjskr)

------------------------------
그리고 어떤 분은 네트워크 전송을 말씀하셨던데,
0xac00 을 utf-8 로 인코딩하면 char * 바이트코드(또는 uint8 *) 가 나오는데.. 그걸 네트워크로 전송하시면 되겠습니다.
------------------------------

"추가 알고리즘 구성해야 하며 이로인해 쓸데 없는 시간 낭비와 비용이 소요됩니다." (sdjskr)

https://en.wikipedia.org/wiki/UTF-8
------------------------------
UTF-8 can encode any Unicode character, avoiding the need to figure out and set a "code page" or
otherwise indicate what character set is in use, and allowing output in multiple scripts at the same time.
------------------------------

익명 사용자의 이미지

이어서 받는 쪽에서는 utf-8 을 받은 것이므로 그걸 사용하시면 됩니다.
glib 에는

gunichar2 * g_utf8_to_utf16 ()
gunichar * g_utf8_to_ucs4 ()
gunichar * g_utf8_to_ucs4_fast ()
gunichar * g_utf16_to_ucs4 ()
gchar * g_utf16_to_utf8 ()
gunichar2 * g_ucs4_to_utf16 ()
gchar * g_ucs4_to_utf8 ()
gint g_unichar_to_utf8 ()

이런 함수들이 있습니다.
이러한 라이브러리를 이용한다면 C언어로 다국어 처리 및 유니코드를 처리하는 것이 매우 쉽게 됩니다.
유니코드가 나온지가 약 20년 정도 되었습니다.
세상이 변했습니다.

익명 사용자의 이미지

원질문자: char []에 "가" 넣으려고 함
sdjskr: "개당 1바이트인 char 배열에 넣는 것 자체가 이미 잘못"
익명1: "더 나은 방법이 나왔다고해서 잘못되었거나 의미가 없거나 하지 않습니다"
sdjskr: "(char 배열에 넣는 것은) 분명히 잘못된 방식이며 현재처럼 메모리가 싼 시점에서는 이제껏 그렇게 사용했다 하더라고 굳이 그렇게 쓸 필요가 없습니다."
익명2(본인): "network cost" - 메모리는 싸졌지만 네트워크 전송시 바이트단위 저장 여전히 쓸 필요있음
익명3: "그리고 어떤 분은 네트워크 전송을 말씀하셨던데, 0xac00 을 utf-8 로 인코딩하면 char * 바이트코드(또는 uint8 *) 가 나오는데.. 그걸 네트워크로 전송하시면 되겠습니다."

응???

익명 사용자의 이미지

이 익명 분은 글을 명료하게 쓰셔야 되겠습니다.
network cost (비용)라고 하셨길래, 네트워크 전송에 대해 말씀드린 겁니다.
네트워크 전송은 모든 경우가 멀티 바이트(char * 또는 uint8 *) 전송입니다.
굳이 cost(비용)을 언급할 필요가 없습니다.

"가"의 유니코드 값이 ac00 이고 이를 utf-8로 표현하면(인코딩하면) EA B0 80 이렇게 됩니다. 멀티 바이트입니다.
이렇게 utf-8 로 변환하여 전송하면 받는 측에서는 utf-8 을 받게 되므로 그걸 사용하면 됩니다.

그런데 sdjskr 이분이 말씀하신 멀티 바이트는 위에 댓글에서 알 수 있듯이,
과거 mb string, wchar 이런 방식으로 한글을 저장하던 방법을 의미합니다.
그래서 오해가 발생하는 것 같습니다.

멀티 바이트라는 개념을
sdjskr님, 익명2님과, 익명3(본인)이 각각 다르게 받아드려서 오해가 발생하는 것 같습니다.

익명 사용자의 이미지

이 익명분은 난독증을 해소하셔야 겠습니다.
비용이라 썼는데 전송에 대해 이야기하는건 또 무슨 경우인지 모르겠네요.

멀티바이트 개념에 대한 오해가아니라 sdjskr 이분이 Windows밖에 모르는 초보라 그런겁니다.
살다살다 utf-8이 웹에서나 쓰이는거란 얘기는 처음들어봅니다. 무지와 용감이 동의어인 세상에 살고있네요.

익명 사용자의 이미지

비생산적인 논쟁은 하고 싶지 않습니다.
저도 utf-8이 웹에서나 쓰이는 거란 얘기는 처음 들어봅니다. 굳이 언급할 가치가 없어서 언급하지 않았습니다.
"network cost" 라고 달랑 이렇게 답변을 다셨길래,
네트워크에서는 모두 멀티바이트 전송인데... 굳이 "network cost"를 언급할 필요가 있냐는 생각이 들어서...
utf-8 이 멀티 바이트라는 얘기를 했던 것인데... 엉뚱한 곳에 답변을 달아 이야기가 엉뚱하게 흘러간 것 같습니다.
아무튼 주말 잘 보내십시오.

익명 사용자의 이미지

char str[3] = "가"; 이렇게 할당하는 것은 제가 보이에는 좀 이상합니다. ... "가" 코드는 0xac00 이므로 uint16 또는 uint32 변수에 저장하면 됩니다.

char[] str = "가"; 대신 uint32_t str[] = "\U0000ac00";라고 해야하지 않나는 말씀이신지요? 일반적으로 후자가 입력하기도 힘들고 가독성이 훨씬 떨어지지 않을까 싶습니다만.

익명 사용자의 이미지

char[] str = "가"; 이렇게 넣어도 되는데...
질문자의 경우처럼 환경에 따라 문제가 발생될 소지가 있습니다.
뭐 뻔히 아시겠지만, C언어에서는 "가" 이것에 대한 코드셋을 지정하는 방법이 없습니다.
편집기가 utf-8 로 저장할 수도 있고 utf-16 으로 저장할 수도 있고 euc-kr로 저장할 수도 있습니다.
질문자의 경우처럼 다양한 환경 때문에 문제가 발생하므로 그런 문제점을 없애려면,
uint16 또는 uint32 변수에 저장하면 됩니다. (그러나 그렇게 작성하기가 불편한 것은 사실입니다.)

libhangul 을 보더라도 그렇고...
iconv 를 보더라도 그렇고...
glib 를 보더라도 그렇고.. 실제 이런 식으로도 코드가 작성되어 있습니다.

그래서 다국어를 위한 메시지 처리는... "안녕하세요" 이렇게 문자열로 하드 코딩하는 방법으로 하지 않습니다.
"hello" 라고 코딩하고 locale 에 해당하는 메시지로 변환하여 "안녕하세요" 또는 "hello" 또는 "중국어", "일본어" 등.. 이렇게 출력을 해야 합니다.
리눅스에서는 .po 파일을 참고하시면 될 겁니다. MS 윈도우에는 이런 방법이 없나요? 아무도 언급하시는 분이 없군요.

익명 사용자의 이미지

C 표준에 스치듯 소스 파일의 인코딩에 대한 언급이 있습니다.

N1570, 5.1.1.2 Translation phases, 1

Physical source file multibyte characters are mapped, in an implementation-defined manner, to the source character set (introducing new-line characters for end-of-line indicators) if necessary.

GCC는 꽤 오래 전부터 VC++는 최신 업데이트부터 그 물리적인 소스 파일 멀티바이트 문자들의 인코딩을 지정하는 옵션 -finput-charset=/source-charset:<iana-name>|.NNNN가 있습니다.

익명 사용자의 이미지

소스코드 파일 내에 지정할 수 있는 방법이 없다는 말입니다.
무슨 말이냐면,
python, ruby 같은 언어는 소스코드 파일 내에 주석으로 지정해 줄 수 있습니다.

# encoding: utf-8
# coding: utf-8
# -*- coding: utf-8 -*-

그런데 C언어에는 이런 방법이 없습니다.

익명 사용자의 이미지

소스코드 파일의 인코딩을 이미 알고 있거나 짐작이 가는 상황(EUC-KR, UTF-8, UTF-8BOM, UTF-16LE 정도?)에서도, 입력의 어려움과 읽기 어려움을 감수할 만큼 여전히 두 방식에 큰 차이가 있는 건가요?

익명 사용자의 이미지

논점이 자꾸 빗나가는데... 질문자의 질문을 읽어보시기 바랍니다.
질문자는 저장된 파일의 인코딩을 모르고, 콘솔 환경의 로케일을 모르는 상황입니다.
컴파일 옵션으로 지정하는 방법은 사람이 직접 해줘야하는 부분입니다.
저장을 euc-kr 로 저장하고, utf-8 이라는 컴파일 옵션을 주어도 컴파일이 되긴 합니다만,
의도한대로 출력이 될까요? 변수 내에 자료가 의도한대로 들어있을까요?
게다가 배열 크기를 고정하였는데, 프로그램이 실행하다가 falut 나는 경우도 있습니다.
그 자체가 잠재적 버그입니다.

만약, C언어 소스코드 내에 인코딩을 표기할 수 있는 기능이 있다면,
C언어 소스코드 내에 인코딩 표기와 저장된 파일의 인코딩이 다를 경우,
컴파일러가 컴파일 에러를 발생시키도록 컴파일러를 설계할 수 있습니다.
따라서 잠재적 버그는 줄어들고 에러 발생시 사람이 파악하기 쉽습니다.
그러나 이러한 기능은 C언어에는 없습니다. 이런 차이점이 있습니다.

익명 사용자의 이미지

아, 원래 질문과 상관없이 일반적으로 혹은 제가 앞으로 문자열 상수를 어떻게 쓰는 게 좋을까 고민 중이라 질문드렸습니다.

EUC-KR 한글이 포함된 소스 파일을 UTF-8로 컴파일하면 Clang의 경우 다음과 같은 경고 메세지를 내주길래, 유니코드 인코딩의 특성상 완벽하지는 않더라도 그 경고 기능에 충분히 의지할 만한 지 아니면 여전히 숫자로 넣어야 하는 지 그와 관련된 경험이 있으시다면 듣고 싶었습니다.

$ clang foo.c
foo.c:2:19: warning: illegal character encoding in string literal
      [-Winvalid-source-encoding]
    char str[] = "<B0><A1>";
                ^~~~~~~~
1 warning generated.

감사합니다.

sdjskr의 이미지

wchar_t 크기가 다른 문제는 리눅스건 윈도우건 나누기 sizeof(wchar_t)로 하면되기 때문에 별도의 추가 알고리즘이 필요없으며 이식성 문제도 전혀 없습니다. 그리고 이미 예시에서 보였듯이 wcslen()같은 Wide Character 대응 함수가 Wide Character의 길이를 정확하게 출력하고 있습니다.

그리고 유니코드(UTF-16)에서 추가적으로 할당된 4-바이트로 구성된 Code Point는 평생 한 번 쓸까말까한 중요성이 없는 문자들이 대부분이기 때문에 무시해도 상관없을 정도입니다. 대부분 2 바이트며, 2바이트만으로 한국어를 모두 표현할 수 있습니다.

그리고 익명 글쓰신 분은 지극히 웹쪽에만 국한된 말씀입니다. C나 C++ 언어는 태생이 시스템용입니다. JAVA나 PHP같은 것들이 등장한 이유이기도 하죠. 멀티 바이트가 그리 좋다면 멀티 바이트를 극구 추천할 테지만 일반적으로 그렇지 않습니다. 비주얼 스튜디오에서도 어느 순간 부터는 멀티바이트를 지양하고 있는 추세입니다. 윈도우의 경우 이미 윈도우 NT 이후로 유니코드를 지원하고 있습니다.

시대에 맞는 추세는 유니코드입니다. 웹은 UTF-8, 시스템은 UTF-16.

익명 사용자의 이미지

"익명 글쓰신 분은 지극히 웹쪽에만 국한된 말씀입니다."
"웹은 UTF-8, 시스템은 UTF-16."

#1

network > web

#2

Firefox 구현 언어:
- Rendering engine: C++
- JavaScript engine: C

Chrome 구현 언어:
- Rendering engine: C++
- JavaScript engine: C++

Safari 구현 언어:
- Rendering engine: C++
- JavaScript engine: C++

Internet Explorer
- 모두 C++

익명 사용자의 이미지

프론트와 백앤드 환경을 구분하셔야죠.

익명 사용자의 이미지

웹에서 사용되는 네트워크 구현에 C/C++를 쓰고있고 걔들은 몽땅 byte 단위로 동작한다는 뜻입니다.
이렇게까지 풀어서 설명해줘야 됩니까?

익명 사용자의 이미지

도무지 무슨 얘기를 하시는건지. 논점 흐트리기의 달인이시네요. YOU WIN!!!!

익명 사용자의 이미지

"가"의 유니코드 값이 ac00 이고 이를 utf-8로 표현하면(인코딩하면) EA B0 80 이렇게 됩니다. 멀티 바이트입니다.

그런데 sdjskr 이분이 말씀하신 멀티 바이트는 위에 댓글에서 알 수 있듯이,
과거 mb string, wchar 이런 방식으로 한글을 저장하던 방법을 의미합니다.

멀티 바이트라는 개념을
sdjskr님, 익명2님과, 익명3(본인)이 각각 다르게 받아드려서 오해가 발생하는 것 같습니다.

sdjskr님이나 익명 분들 모두 유니코드, 인코딩, 멀티 바이트에 대해 알고 계십니다.
다만, 용어 해석에서 상호 오해가 발생하여 무의미한 토론이 되는 것 같습니다.
다들 즐겁고 행복한 주말 보내시기 바랍니다.

익명 사용자의 이미지

(다른 익명입니다)
프론트건 백이건 하이레벨이건 로우레벨이건 네트웍은 바이트 기반이라는 설명이네요.
자기가 이해못하면 논점흐르기라며 비꼬는건 좀 아니네요.

익명 사용자의 이미지

읽고 쓰고합니다.

익명 사용자의 이미지

그러니깐요. 애초에 <웹은 UTF-8, 시스템은 UTF-16.>라는 얘기가 틀렸다고요.
오히려 <시스템은 UTF-8, 웹은 UTF-16(JavaScript가 UCS-2나 UTF-16을 쓸 수 있죠)>라고 하면 이해해볼 여지라도 있겠지만요.

익명 사용자의 이미지

실제로 OS에서는 UTF-16을 사용하고 있습니다. 한참 됐죠 이미. 이는 1바이트 단위로만으로는 다국어 표현의 한계점이 분명히 존재하기 때문입니다.

그리고 웹에서 UTF-8을 추구하는 건 바로 영어 때문입니다. 영어는 여전히 1바이트 인데 굳이 16비트에 넣는 건 낭비이기 때문이죠.

하지만 빠른 로컬 시스템에서는 그닥 영향을 받지 않습니다. 오히려 더 빠르죠. 일괄적으로 처리하니.

웹용은 UTF-8 이고 시스템은 UTF-16 가 틀렸다는 정보는 어디에도 없습니다.

kukyakya의 이미지

많은 리눅스 시스템이 utf8을 사용하고 있습니다.

윈도우즈에서 utf-16을 사용한다고 해서 utf8은 웹용이고 시스템은 utf16이라는 표현하는 것은 부적절합니다.

익명 사용자의 이미지

재밌네요.
태어나서 리눅스 한번 안깔아보고 윈도우즈만 겨우 쓸줄아는 초보의 실언 정도로 이해할께요.
다른데 가선 그런 얘기하지 마세요. 사람들이 속으로 비웃어요

익명 사용자의 이미지

http://www.w3schools.com/charsets/ref_html_utf8.asp

utf-8 이 웹용으로 적절하다는 말은 여기서도 있습니다. 이분도 실언인가요? 무턱대고 리눅스에서 utf 8을 쓰니 최고다? 무조건 한글은 3바이트를 차지하는 데 그걸 좋다고 절대적으로 쓰는 것이야 말로 진정한 무지이죠. 인코딩은 필요에따라 적재 적소에 사용하는겁니다. 한글이 얼마를 차지하는지 신경도 안쓰는 소프트웨어 세상에서 휘둘리고 있는겁니다. 어디가서 그런 소리 하지 마세요. 고수들이 대놓고 웃습니다.

우물안 개구리가 따로없군요.

익명 사용자의 이미지

예를 들고 올라면 제대로 이해나 하고 들고옵시다.
삶은 계란이 아침 식사로 적절하다고하면 삶은 계란은 아침으로나 먹으라는 얘기가 아니라
다른 때도 좋지만 아침 식사용으로 좋다는 뜻이죠.
그럼 JS는 태생이 시스템 언어라서 utf-16을 쓰고 있나요?

utf-8이 만능이니 utf-16 버리고 utf-8만 쓰잔 얘기가 아니라
utf-8이 웹에서나 쓰는거고 다른 곳(시스템)에선 utf-16 써야 한다는게 헛소리라는 얘기입니다.
utf-16 쓰는 시스템이있듯 utf-8 쓰는 시스템도 있는데
utf-8은 웹, utf-16은 시스템이라는 이분법을 들고오니 반론이 나오는거죠.

다른 분들 글도 보시죠. 도무지 이해 안되는게
"utf-8은 웹용, utf-16은 시스템용"이라는 이분법적 헛소리라고들 하고 있죠.

반례 들어 틀린거 알려주면 공부할 생각은 안하고 되도않는 예나 들고와서 우겨볼라고 하다니 참...

sdjskr의 이미지

UTF-8은 반드시 웹용으로 사용하고, UTF-16은 반드시 시스템용으로 사용하라는 문구가 어디 있죠?
이분법으로 몰아가는 것은 님이죠. 자기 논리에 구겨 맞추려고 확대 고정 해석하는 님이나 우기지 마세요.
헛소리는 누가 하는 건지. 어이가 없군요.

kukyakya의 이미지

그렇네요 utf-16은 웹용이고 utf-8은 시스템용인데 다들 왜 이러시는걸까요?

익명 사용자의 이미지

자기가 한 말을 왜 나보고 기억해달라는 건지...

글쓴이: sdjskr 작성 일시: 금, 2016/03/18 - 5:33오후
"개당 1바이트인 char 배열에 넣는 것 자체가 이미 잘못된 거죠. 결과 값 또한 아무런 의미가 없습니다."

글쓴이: sdjskr 작성 일시: 금, 2016/03/18 - 8:24오후
"char[] 에 leading byte와 tail byte로 구성시켜 한글을 집어 넣는 방식은 1바이트의 가격이 매우 비싸던 시절 어쩔 수 없이 어거지로 하던 방식이며"
"분명히 잘못된 방식이며 현재처럼 메모리가 싼 시점에서는 이제껏 그렇게 사용했다 하더라고 굳이 그렇게 쓸 필요가 없습니다."

글쓴이: sdjskr 작성 일시: 토, 2016/03/19 - 12:33오전
"시대에 맞는 추세는 유니코드입니다. 웹은 UTF-8, 시스템은 UTF-16."

참고로 utf-8은 개당 1바이트인 char 배열에 넣는 방식이고 값도 의미가 있는 경우입니다.
님이 말하는 어거지로 하던 방식이 바로 utf-8이죠.

utf-8이 웹에서나 쓰는 방식이라는 이야기가 없었다면 이런 답변은 나오지도 않았겠죠.

글쓴이: 익명 사용자 작성 일시: 토, 2016/03/19 - 12:55오전
"utf-8 은 웹 뿐만 아니라 리눅스 시스템에서도 많이 사용됩니다."

최소한 자기가 먼말을 했는지는 기억하는 사람하고 얘기를 하고싶네요.

sdjskr의 이미지

분명히 영어는 1바이트인데 굳이 2바이트에 넣기에는

낭비기 때문에 대부분 영어 스크립트로 이루어진 웹에서 굳이 2바이트 단위를 쓸필요가 없다는 얘긴데. 그리고 웹에서만 쓰는 방식이라고 누가 그랬는지?

story making의 대가시네요.

기억력 또한 치매 수준이고. 결정적으로 자기 논리는 없고, 반박을 위한 반박 뿐. 이는 곧 지능이 떨어진다는 결론 밖에는 없네요.

수준 떨어지니 좀 꺼져 주시죠. 더 이상 상대 가치가 없으니 이제부터 무시해드리겠습니다.

익명 사용자의 이미지

애초에 댓글다는 수준봐서는 이수준 이상의 댓글이 나올거란 기대는 안했습니다.
그냥 "제가 윈도우즈에 익숙하다보니, 다른 시스템에선 utf-8을 많이 사용하고 있었군요."
이거 한마디가 알량한 자존심때문에 어려운거겠지요.
알지못하는게 문제가 아니라 배울려고하지 않는게 문제인데 말이죠.

기억력도 치매 수준이고 자기 논리도 없고 반박을 위한 반박만 하고 결론적으로 지능이 떨어지는 저한테 발리는 님은 대체 어떡할지..

꺼지건 말건 제마음이니 신경안쓰셔도 돼고 담부턴 제대로 아는것만 떠들면 만날일도 없을겁니다.
애초에 열심히 댓글단건 다른분들이 님같은 초보답변이 진실인줄 알고 다른곳에 가서 똑같이떠들까 그런거지
님한테 알려줄 의도가 있었던것도 아니었습니다.

무시해주신다니 감사한 마음으로 떠납니다.

익명 사용자의 이미지

참 이걸 빼먹었네요.

ECMA에 메일쓰세요.
대부분 영어 스크립트로 이루어진 웹에서 굳이 2바이트 단위를 쓸필요가없는데
왜 자바스크립트는 utf-16나 ucs-2를 쓰고있냐고 말이죠..
(자바스크립트가 태생이 시스템 언어라고 하실까 덜컥 겁이나네요)

마지막까지 무식을 떨치시니 감히 제가 감당할수있는 분이 아니구나.. 느껴집니다.

익명 사용자의 이미지

UTF-8이 UTF-16보다 우월하다는 얘기가 아닙니다. UTF-8이 많이 쓰이고 있고, UTF-8로 인코딩 문자열을 다룰 때는 char[]를 사용한다는 얘기입니다.

논란의 시발점이 된 글들을 발췌 인용하겠습니다. 논란이 되는 부분은 제가 볼드체로 강조하였습니다:

제목: 한글 문자를 제대로 표현하려면 C++의 wide character와 해당 함수를 사용해야 합니다.

CP949 던 유니코드던 한글은 한 문자당 2 바이트 이상(UTF-8는 3 바이트, UTF-16는 2 바이트)인데 개당 1바이트인 char 배열에 넣는 것 자체가 이미 잘못된 거죠. 결과 값 또한 아무런 의미가 없습니다.

분명 이 글에서 UTF-8을 char[]에 저장하는 것은 잘못된 것이라고 얘기하고 있습니다. 그래서, 여러분들이 그렇지 않다고 지적하고 있는 것입니다.

제목: 다국어 지원이 제대로 안되던 시절의 유물일 뿐입니다.

char[] 에 leading byte와 tail byte로 구성시켜 한글을 집어 넣는 방식은 1바이트의 가격이 매우 비싸던 시절 어쩔 수 없이 어거지로 하던 방식이며,

상동.

이 경우 영어와 한글이 섞어 있을 경우 스트링 처리할 때, 어느것은 1 바이트 어느 것은 2 바이트이기 때문에 word counting의 경우 추가 알고리즘 구성해야 하며 이로인해 쓸데 없는 시간 낭비와 비용이 소요됩니다. 또한 문자가 많으면 많을 수록 성능 문제 또한 무시할 수 없습니다. 분명히 잘못된 방식이며 현재처럼 메모리가 싼 시점에서는 이제껏 그렇게 사용했다 하더라고 굳이 그렇게 쓸 필요가 없습니다.

sizeof(wchar_t)가 4이고 고정폭 인코딩인 UTF-32(엄밀히 말하면 UCS-4)를 사용하는 환경에서는 이 말은 옳습니다. 그러나, 윈도우는 wchar_t[]는 가변폭 인코딩인 UTF-16을 사용합니다. 따라서, 다른 가변폭 인코딩(EUC-KR, UTF-8)와 마찬가지로 여전히 문자 수를 셀 때 그 추가 알고리즘이란 게 필요합니다. (인용한 글에서는 "word counting"이라고 하셨지만, 문맥 상 문자 수 세기를 의미한다고 해석했습니다.) 댓글 중 이식성에 대한 다른 스레드에서 이 부분에 대해 자세히 얘기하고 있으니 더 자세한 사항은 그 쪽을 참고하세요.

사실 엄밀히 C 표준을 적용하자면 wchar_t[]랑 가변폭 인코딩은 어울리지 않습니다. C 표준에서는 wchar_t를 다음과 같이 정의하고 있습니다:

N1548, 3.7.3

wide character

bit representation that fits in an object of type wchar_t, capable of representing any character in the current locale

즉, 현재 로케일에 포함된 모든 문자는 하나의 wchar_t로 표현되어야 합니다. 따라서, C 표준에 따르면 wchar_t[]도 고정폭 인코딩이어야 합니다.

사실 윈도우도 윈도우 2000 전까지는 가변폭 인코딩 UTF-16이 아닌 고정폭 인코딩인 UCS-2를 사용했었습니다. 따라서, UCS-2에 딱 맞게 wchar_t의 크기를 2바이트로 정한 것은 적어도 그 당시 기준으로는 합리적인 결정이었다고 생각합니다. UCS-2를 등장할 당시에는 코드 공간(code space)가 2^16이면 세상 사람들은 필요한 문자와 기호를 다 표현할 수 있을 줄 알았습니다. UCS-2를 사용하던 유니코드 1.0의 Introduction에서 인용합니다:

With over 30,000 unallocated character positions, the Unicode character encoding provides sufficient space for foreseeable future expansion.

그런데, 그 가정은 몇 년 사이에 깨져버렸고 더 많은 공간이 필요하다는 것을 우리는 깨달았습니다.

이 시점에서 마이크로소프트는 선택을 해야했을 겁니다. 고정폭 인코딩(예를 들어, UTF-32)을 계속 사용하되 wchar_t를 크기를 늘릴 것인가? 아니면 현재 크기를 유지하되 가변폭 인코딩 UTF-16을 사용할 것인가? C 표준을 생각하면 전자를 택해야겠으나, 그러면 기존 코드와의 바이너리 호환성이 박살이 납니다. 따라서, 후위 호환성이 굉장히 중요하게 여기는 마이크로소프트 입장에서는 후자를 선택할 수 밖에 없지 않았나 추측해봅니다.

노파심에 다시 한 번 말하지만, UTF-8이 UTF-16 낫다는 얘기가 아닙니다. 윈도우 API는 입력 문자열이 UTF-16이라고 가정하고 있기 때문에, 윈도우에서 코딩할 때 프로그램 내부에서 UTF-16에 wchar_t[]를 사용하는 건 거의 필수적이고 권장되는 방식입니다. (물론, 현재 wcslen() 등 여러 API가 UCS-2를 벗어난 UTF-16을 제대로 지원해주지 못하고 있는 것은 아쉽습니다.) 다만, 그렇다고 일반적으로 "char 배열에 넣는 것 자체가 이미 잘못된 거죠"라거나 "어쩔 수 없이 어거지로 하던 방식"라고 말하는 건 UTF-8 인코딩 문자열을 char[]에 저장하는 것을 고려하지 않는 오류가 있는 발언입니다.

익명 사용자의 이미지

아, 논란의 시발점의 된 글 발췌 인용에서 하나 빠뜨렸네요. 논의가 빙빙 돌지 않는데 도움이 되었으면 좋겠습니다.

제목: wchar_t 크기가 다른 문제는 나누기 sizeof(wchar_t)로

wchar_t 크기가 다른 문제는 리눅스건 윈도우건 나누기 sizeof(wchar_t)로 하면되기 때문에 별도의 추가 알고리즘이 필요없으며 이식성 문제도 전혀 없습니다. 그리고 이미 예시에서 보였듯이 wcslen()같은 Wide Character 대응 함수가 Wide Character의 길이를 정확하게 출력하고 있습니다.

그리고 익명 글쓰신 분은 지극히 웹쪽에만 국한된 말씀입니다. C나 C++ 언어는 태생이 시스템용입니다. JAVA나 PHP같은 것들이 등장한 이유이기도 하죠.

멀티 바이트가 그리 좋다면 멀티 바이트를 극구 추천할 테지만 일반적으로 그렇지 않습니다. 비주얼 스튜디오에서도 어느 순간 부터는 멀티바이트를 지양하고 있는 추세입니다. 윈도우의 경우 이미 윈도우 NT 이후로 유니코드를 지원하고 있습니다.

시대에 맞는 추세는 유니코드입니다. 웹은 UTF-8, 시스템은 UTF-16.

여기서, "멀티바이트"는 마이크로소프트의 MBCS로 CP949와 같은 레거시 인코딩을 뜻하시는 듯하니, "가변폭 인코딩" 등과 혼동없으시기 바랍니다.

sdjskr의 이미지

이 쓰레드의 결론으로도 무방할 듯합니다.

지금 이 쓰레드의 상황은 교과서적으로 습득한 지식과 역사를 고려한 실제 상황과의 논의라고나 할까요.

인코딩의 역사를 모르고 위키나 구글링에만 의존하게 되면 이렇게 장황해지는 겁니다.

익명 사용자의 이미지

자기가 쓴글도 모르는분이 인코딩의 역사는 아시나보군요!

sdjskr의 이미지

님이 전제하시고 있는 것은 다 이해하고 있는 내용입니다. 그리고 저의 요지는 한글을 비롯한 대부분의 문자는 16bit wchar_t 만으로도 표현이 가능하다는 일반적인 편의성을 이야기하고 있는건데, 굳이 무턱대고 char에 한글을 넣던 예전 방식을 고집하니 이것을 문제 삼고 있는것이고요. 추가 알고리즘 부분 또한 전혀 부정하는 것이 아니라, 2바이트 이외의 문자들은 그다지 중요성이 없는 문자들로 구성되어서 무시할 수 있을 정도라는 것이 저의 일관된 전제입니다. 당연히 그것까지 들어갈 환경이라면 알고리즘을 구성해야겠죠. 그게 아니라면 컴팩트하게 가는 것이고요. 이런건 하나의 융통성 문제입니다. 이점은 논리의 흐름이 일관되기 때문이 굳이 반복적으로 길게 또 설명할 필요가 없는 부분이었습니다.

부연 설명 없이 짧게 문장을 구성하다 보니 여러분들이 오해를 하고 있는 것 또한 사실이고요. 그리고 생각이 다르다고 해서 매도하는 분위기는 지극히 커뮤너티 자체를 지극히 후진적으로 몰고 가는 것으로 보입니다.

익명 사용자의 이미지

인터넷 게시판에서 학계 논문 수준의 엄밀함을 기대하는 것도 어렵지만, 그걸 감안하더라도 쓰신 글들은 본인 의도를 더 분명하게 전달할 수 있도록 다듬을 수 있지 않을까 싶습니다.

> 님이 전제하시고 있는 것은 다 이해하고 있는 내용입니다. 그리고 저의 요지는 한글을 비롯한 대부분의 문자는 16bit wchar_t 만으로도 표현이 가능하다는 일반적인 편의성을 이야기하고 있는건데,

그런 요지라면 "1) Visual C++ 하에서 2) 영어와 한글을 포함한 기본 다국어 영역(BMP)의 문자로 충분한 경우라면, wchar_t[]를 쓰는 게 편해요"라고 쓰셨다면, 다들 고개를 끄떡였거나 윈도우 환경에서는 그런가 보다라고 했을 겁니다. 그런데, 처음에 쓰신 글들에서 두 가정을 명시적으로 언급하지 않으신 채 그냥 ​결론만 부분만 언급하시니 많은 분들이 본인 의도와 다르게 이해하신 거라고 봅니다. 리눅스에서는 안 그런데라든가, wchar_t[]가 항상 고정폭 인코딩인 것은 아닌데라든가. 원글이 Visual C++에 관한 질문이었다 하더라도, 그렇게 단호하고 강한 어조로 말씀하시려면 KLDP의 L이 Linux임을 고려하여 처음 쓰신 글이라든가 이어진 초반 댓글에서 그 가정들을 명확히 해주셨으면 의사소통이 더 잘 되지 않았을까 싶습니다.

> 굳이 무턱대고 char에 한글을 넣던 예전 방식을 고집하니 이것을 문제 삼고 있는것이고요.

어떤 글에서 그렇게 무턱대고 고집하고 있다고 느끼신 건가요?

> 추가 알고리즘 부분 또한 전혀 부정하는 것이 아니라,

그렇다면, "wchar_t 크기가 다른 문제는 리눅스건 윈도우건 나누기 sizeof(wchar_t)로 하면되기 때문에 별도의 추가 알고리즘이 필요없으며 이식성 문제도 전혀 없습니다."라는 표현은 피했어야 하지 않았을까요?

> 2바이트 이외의 문자들은 그다지 중요성이 없는 문자들로 구성되어서 무시할 수 있을 정도라는 것이 저의 일관된 전제입니다. 당연히 그것까지 들어갈 환경이라면 알고리즘을 구성해야겠죠. 그게 아니라면 컴팩트하게 가는 것이고요. 이런건 하나의 융통성 문제입니다.
> 이점은 논리의 흐름이 일관되기 때문이 굳이 반복적으로 길게 또 설명할 필요가 없는 부분이었습니다.

저는 sdjskr 님께서 이전 글 중에서 그렇게 설명하신 글을 찾을 수 없었습니다. 익명 글 중에 sdjskr 님께서 쓰신 글이 있다 치더라도, 그렇게 얘기하신 건 다른 분 혹은 분들이 코드까지 적어가며 여러 차례 설명하신 이후에나 그렇게 쓰신 게 됩니다. 그러니까 sdjskr 님의 초반 글들을 바탕으로 윈도우 wchar_t[]가 고정폭 인코딩을 사용한다고 오해하고 계신가 아닌가 하고 여러 차례 설명하여 드리려 한 거라고 봅니다.

> 그리고 생각이 다르다고 해서 매도하는 분위기는 지극히 커뮤너티 자체를 지극히 후진적으로 몰고 가는 것으로 보입니다.

가치관이 개입할 수 있는 문제를 한 쪽으로 몰아가는 것은 피해야겠지만, 제가 보기에는 지금 논의되고 있는 점들은 기술적인 문제이지 가치관 문제는 아닌 듯합니다. 물론, 그렇게 보는 것 자체가 하나의 가치관이라고 말씀하신다면 저도 딱히 드릴 말씀은 없습니다.

@ 물론, 분명 다른 분들의 몇몇 글들에서 빈정거림과 지나치게 사나운 반응 아닌가 하는 느낌도 있습니다. 쓰고 나서, 이 글도 그런 사나운 반응 중의 하나 아닌가 싶기도 하고, 제가 이런 글 쓸 자격이 있는가 싶기도 하고, 이미 상당한 신뢰가 쌓인 사이가 아닌 이상 이런 글이 좋게 들리기 어려울 텐데 과연 어떤 의미로든 플러스가 되는 글일까 싶기도 합니다. 그래도, 꽤 시간들여 공들여 썼기에 포스팅하겠습니다. 좋게 봐주셨으면 좋겠습니다.

익명 사용자의 이미지

utf-8 은 웹 뿐만 아니라 리눅스 시스템에서도 많이 사용됩니다.

익명 사용자의 이미지

wchar_t 크기가 다른 문제는 리눅스건 윈도우건 나누기 sizeof(wchar_t)로 하면되기 때문에 별도의 추가 알고리즘이 필요없으며 이식성 문제도 전혀 없습니다.

wchar_t의 크기에 따라 알고리즘이 달라집니다. 예를 들어, 한 문자가 항상 하나의 wchar_t에 대응하면 문자 갯수를 셀 때 단순 배열 크기 계산으로 충분하지만, 그렇지 않은 경우 다른 알고리즘을 사용해야 합니다.

그리고 이미 예시에서 보였듯이 wcslen()같은 Wide Character 대응 함수가 Wide Character의 길이를 정확하게 출력하고 있습니다.

VC++의 wcslen()이 윈도우 내부 인코딩인 UTF-16을 충실히 구현하고 있다면, 단순히 배열 크기 계산만으로는 부족합니다. 따라서, wchar_t를 사용하더라도 여전히 배열 크기 계산을 넘어선 추가 알고리즘 이 필요하다는 뜻이었습니다.

그리고 유니코드(UTF-16)에서 추가적으로 할당된 4-바이트로 구성된 Code Point는 평생 한 번 쓸까말까한 중요성이 없는 문자들이 대부분이기 때문에 무시해도 상관없을 정도입니다. 대부분 2 바이트며, 2바이트만으로 한국어를 모두 표현할 수 있습니다.

그런 경우 한글 지원이라고는 말할 수 있어도, 유니코드 세상에서 다국어를 제대로 지원한다고는 말하기 어렵다고 생각합니다.

그리고 익명 글쓰신 분은 지극히 웹쪽에만 국한된 말씀입니다. C나 C++ 언어는 태생이 시스템용입니다. JAVA나 PHP같은 것들이 등장한 이유이기도 하죠. 멀티 바이트가 그리 좋다면 멀티 바이트를 극구 추천할 테지만 일반적으로 그렇지 않습니다. 비주얼 스튜디오에서도 어느 순간 부터는 멀티바이트를 지양하고 있는 추세입니다. 윈도우의 경우 이미 윈도우 NT 이후로 유니코드를 지원하고 있습니다.

시대에 맞는 추세는 유니코드입니다. 웹은 UTF-8, 시스템은 UTF-16.

MS 때문에 용어 사용에 혼란이 있는 것 같습니다. UTF-8도 UTF-16도 멀티바이트 인코딩입니다. 아래에 위키피디아를 인용합니다. UTF-8 자체는 byte-oriented이기 때문에, char[]wchar_t[]보다 더 자연스럽습니다.

https://en.wikipedia.org/wiki/Variable-width_encoding

A variable-width encoding is a type of character encoding scheme in which codes of differing lengths are used to encode a character set (a repertoire of symbols) for representation in a computer. Most common variable-width encodings are multibyte encodings, which use varying numbers of bytes (octets) to encode different characters. (Some authors, notably in Microsoft documentation, use the term multibyte character set, which is a misnomer since representation size is an attribute of the encoding, not of the character set.)

...

The Unicode standard has two variable-width encodings: UTF-8 and UTF-16 (it also has a fixed-width encoding, UTF-32).

익명 사용자의 이미지

a를 넣던 가를 넣던. 이분은 wchar_t 가 무슨 타입인지도 잘 모르신채 글을 쓰고 있는 듯

익명 사용자의 이미지

 
#include <stdio.h>
#include <wchar.h>
 
int main()
{
    wchar_t str[] = L"\U0001F600";  /* 'GRINNING FACE' (U+1F600) */
#ifdef _WIN32
    printf("%Iu\n", sizeof(wchar_t));  /* 2 */
    printf("%Iu\n", wcslen(str));  /* 2 */
    printf("%Iu\n", sizeof(str) / sizeof(str[0])); /* 3 */
#else
    printf("%zu\n", sizeof(wchar_t));  /* 4 */
    printf("%zu\n", wcslen(str));  /* 1 */
    printf("%zu\n", sizeof(str) / sizeof(str[0]));  /* 2 */
#endif
}

익명 사용자의 이미지

동일 시스템에서 어떤 문자든 wchar_t 크기가 동일하다는 겁니다. 4바이트 인 환경과 2바이트인 서로 다른 환경을 비교해 놓고 다르다고 이야기 하시니 이게 도대체 무슨 논리인지.

익명 사용자의 이미지

유니코드 단일 문자(예를 들어, 'GRINNING FACE' (U+1F600))가 wchar_t의 크기(sizeof(wchar_t))에 따라 차지하는 wchar_t의 개수가 (sizeof(str) / sizeof(str[0])wcslen()의 결과에서 확인할 수 있듯이) 다르다는 이식성(portability) 얘기를 해오고 있습니다.

그리고, 혹시 한 시스템에서 유니코드 문자는 항상 동일한 수의 wchar_t를 차지한다는 얘기시라면, VC++에서는 그렇지 않습니다:

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

int main()
{
    wchar_t str[] = L"\U000000B1\U0001F600";  /* 'PLUS-MINUS SIGN' (U+00B1) and 'GRINNING FACE' (U+1F600) */

    printf("%Iu\n", sizeof(wchar_t));  /* 2 */
    printf("%Iu\n", wcslen(str));  /* 3 */
    printf("%Iu\n", sizeof(str) / sizeof(str[0])); /* 4 */
}

마지막 출력에서 널 문자를 제외하면 그 값이 3으로서, 'PLUS-MINUS SIGN'와 'GRINNING FACE'가 동일하지 않은 수의 wchar_t를 차지함을 알 수 있습니다.

익명 사용자의 이미지

1 바이트 단위의 char에 2 바이트를 넣게 되니, 리드 바이트와 테일 바이트로 구성되듯이, 님 또한 2바이트 단위의 wchar_t 배열에 4바이트를 넣게 되니, wchar_t 원소에 문자 하나가 다 들어가지 못하고, 리드 바이트와 테일 바이트로 구성되어 같은 시스템이라 하더라도 결과 값이 다르게 나오는 겁니다. 굳이 이렇게 한다면 4바이트가 들어갈 경우에 대비한 알고리즘이 필요하겠죠. 이는 이미 코딩 전부터 누구나 염두하고 있는 지극히 기초적인 사항입니다.

하지만, 지극히 잘 쓰지도 않는 특정 문자만을 예를 들어 일반화 시키는 것을 타당하지 않습니다. 저런 문자 몇 몇 때문에 알고리즘을 구성해야한다는 것이 경제성이 있을지는 의문입니다. 그리고 흔히 사용하는 언어와 문자는 UTF-16의 2바이트 영역에 있는 코드 포인트만으로도 충분합니다.

UTF-16 기본 유닛이 16비트인 이유가 있는겁니다.

kukyakya의 이미지

조금 바꿔서 표현해볼까요?

Quote:

하지만, 지극히 잘 쓰지도 않는 non-alphabet character를 예를 들어 일반화 시키는 것을 타당하지 않습니다. 저런 문자 몇 몇 때문에 알고리즘을 구성해야한다는 것이 경제성이 있을지는 의문입니다. 그리고 흔히 사용하는 언어와 문자는 char의 1바이트 영역에 있는 코드 포인트만으로도 충분합니다.

대부분의 환경에서 CHAR_BIT이 8비트인 이유가 있는겁니다.

어떤 느낌이신가요?

char 하나가 환경에 따라 문자 하나가 아닐 수 있듯이 wchar_t 또한 그렇습니다. 16 bit면 충분하다고 하셨는데 CJK Unified Ideographs Extension B(http://www.unicode.org/charts/PDF/U20000.pdf) 만 보더라도 16bit wchar_t 하나로는 표현이 불가능합니다.

'주로 사용되는 글자는 16 bit면 충분하다'는 주장에는 동의합니다만, '16 bit wchar_t 하나가 유니코드 문자 하나에 해당된다'는 주장에는 동의할 수 없습니다. 애초에 wchar_t의 인코딩에 대해서는 표준에서 명시하지도 않고 있구요.

익명 사용자의 이미지

기본 단위가 2바이트씩이나 되는 UTF 16과 비교는 적절한 비유가 못됩니다. 상황이 완전 다르죠. 전자는 필수인 한글을 넣기에 기본단위가 너무 작아서 부득이하게 테일 바이트를 붙이지만, UTF 16은 널널합니다. 그다지 중요성이 없는 문자를 4바이트 역영에 추가한 것일 뿐이구요. 그리고 wchar t 기본 사이즈가 동일하다했지, 한 문자가 다 들어간다는 표현은 없습니다. 리드 바이트와 테일 바이트의 구성에 대해 언급한 것 보시면 알 수 있죠.

kukyakya의 이미지

wchar_t의 기본 사이즈가 동일하다는 게 어떤 의미인가요?

utf16이 널널하다는 표현도 이상합니다. utf16 또한 utf8처럼 가변길이 인코딩인데 뭐가 널널하다고 하시는건가요?

익명 사용자의 이미지

wchar_t가 2 바이트인 시스템에서는 4바이트 문자를 집어넣는다 해도 여전히 2 바이트라는 단순한 얘기입니다.
단, 2바이트만으로는 부족한 문자의 경우 꼬리를 붙혀가는 방식으로 4바이트를 문자를 표현한다는 겁니다. 이 부분은 계속 얘기하는 부분인데요.

UTF-16이 널널하다는 말은 1 바이트 char에 한글을 넣으면 부득이하게 테일바이트를 사용해야 하지만, UTF-16에서는 테일 바이트 필요없이 기본 단위, 16 비트 만으로도 대부분의 문자 표현에 충분하다는 이야기입니다.

그냥 디폴트 값 자체가 8비트에 비해 다국어 지원에 널널하단 겁니다. 실례로 한글 가를 담을 경우 UTF-16은 고작 2바이트에 불과하지만, UTF-8에서는 테일바이트가 추가되기 때문에 3바이트가 되어버리니 더 많은 용량을 차지하게 되죠.

UTF 뒤에 붙는 8, 16, 32는 가변길이가 아니라 기본 유닛을 이야기 하는겁니다. UTF-8의 경우 8비트를 에 담고 이보다 커질 경우 기본 유닛인 8비트씩 추가해서 총 32비트까지 가능한 것이고요.

UTF-16은 16비트가 추가로 더해지기 때문에 2바이트와 4바이트 짜리가 있는 것이죠. UTF-32은 기본 유닛이 32비트라 모든 문자가 32비트라는 겁니다.

kukyakya의 이미지

Quote:

wchar_t가 2 바이트인 시스템에서는 4바이트 문자를 집어넣는다 해도 여전히 2 바이트라는 단순한 얘기입니다.
단, 2바이트만으로는 부족한 문자의 경우 꼬리를 붙혀가는 방식으로 4바이트를 문자를 표현한다는 겁니다. 이 부분은 계속 얘기하는 부분인데요.

그러니까 이 부분이 잘못된 부분이라 말씀드리는겁니다. 말씀하시는 UTF-16은 wchar_t와는 상관이 없습니다. 윈도우즈에서 wchar_t에 utf-16을 사용할 뿐이죠. 애초에 wchar_t의 인코딩을 가정하고 논의를 하는 것이 의미가 없습니다.

Quote:

UTF-16이 널널하다는 말은 1 바이트 char에 한글을 넣으면 부득이하게 테일바이트를 사용해야 하지만, UTF-16에서는 테일 바이트 필요없이 기본 단위, 16 비트 만으로도 대부분의 문자 표현에 충분하다는 이야기입니다.
그냥 디폴트 값 자체가 8비트에 비해 다국어 지원에 널널하단 겁니다. 실례로 한글 가를 담을 경우 UTF-16은 고작 2바이트에 불과하지만, UTF-8에서는 테일바이트가 추가되기 때문에 3바이트가 되어버리니 더 많은 용량을 차지하게 되죠.

이 부분도 한글로 한정하자면 맞는 얘기지만 영문자 기준으로 하면 다른 얘깁니다. 알파벳은 utf-8에서는 1byte만 차지하지만 utf-16으로 인코딩하면 2byte가 되죠. 다국어 지원의 가/불가 여부와 용량 문제를 왜 엮고 계시는건가요? 말씀하신대로 표현하면 utf-8의 디폴트 값이 8bit라 다국어 지원이 힘든건가요? 둘은 전혀 상관없습니다.

UTF-8이나 UTF-16 등의 인코딩을 정해놓은 상황이라면 char[]나 char16_t[] 등을 이용하는 것이 좀 더 목적에 부합하는 방법이고, '유니코드'를 위해 system dependent한 wchar_t를 이용하는 것은 오히려 피해야할 방법입니다.

wchar_t 논의에 유니코드 인코딩 얘기가 얽히고 섥혀서 점점 산으로 가는 것 같네요.

익명 사용자의 이미지

그 문제로 여기까지 이어지게 된 것이고. 그리고 님의 논리는 명료하지가 못하고 좀 중구 난방입니다. 그러니 산으로 갈 수 밖에 없죠.

kukyakya의 이미지

이해를 하지 못하신다니 매우 안타깝습니다.

익명 사용자의 이미지

어떤 분, 어떤 글, 어떤 부분에서 wchar_t의 크기가 한 시스템에서 변한다고 얘기하고 있다는 건지 구체적으로 인용해주실래요?

익명 사용자의 이미지

1 바이트 단위의 char에 2 바이트를 넣게 되니, 리드 바이트와 테일 바이트로 구성되듯이, 님 또한 2바이트 단위의 wchar_t 배열에 4바이트를 넣게 되니, wchar_t 원소에 문자 하나가 다 들어가지 못하고, 리드 바이트와 테일 바이트로 구성되어 같은 시스템이라 하더라도 결과 값이 다르게 나오는 겁니다. 굳이 이렇게 한다면 4바이트가 들어갈 경우에 대비한 알고리즘이 필요하겠죠. 이는 이미 코딩 전부터 누구나 염두하고 있는 지극히 기초적인 사항입니다.

반면, wchar_t가 4바이트 시스템에서는 일어나지 않는 일입니다. 따라서, 그 시스템에서 잘 동작하도록 작성된 코드가 wchar_t의 크기가 2바이트인 시스템에서는 다른 동작을 보일 수 있습니다. 결국, 이식성을 고려한다면 두 시스템을 오가며 wchar_t의 크기에 따라 달라질 수 있는 wcslen() 등 문자열 관련 함수와 메모리 사용량을 일일이 파악하고 확인해야 할 겁니다. 그보다는, 선택할 수 있다면, UTF-8 인코딩 하에서 strlen()처럼 익숙해서 원하는대로 동작할 지 안 할지 예상 가능한 함수들과 char[] 배열을 사용하는 게 더 일관적이라 작업하기 편하지 않을까요?

하지만, 지극히 잘 쓰지도 않는 특정 문자만을 예를 들어 일반화 시키는 것을 타당하지 않습니다. 저런 문자 몇 몇 때문에 알고리즘을 구성해야한다는 것이 경제성이 있을지는 의문입니다. 그리고 흔히 사용하는 언어와 문자는 UTF-16의 2바이트 영역에 있는 코드 포인트만으로도 충분합니다.

UTF-16 기본 유닛이 16비트인 이유가 있는겁니다.

네, 해당 애플리케션을 다른 시스템으로 이식할 가능성이 없고 BMP 영역의 문자만으로 충분하다고 판단되면 그게 공학적인 선택일 수도 있겠습니다. 다만, 그럴 때는 UTF-16이 아니라 UCS-2 인코딩을 사용한다고 말해야겠습니다.

--

저는 이 댓글의 첫문단을 읽고 나자 처음 댓글의 다음 문단이 무엇을 말씀하려고 하셨던 건지 이제 전혀 갈피를 못 잡겠습니다.

wchar_t 는 무슨 문자를 넣던 크기가 동일합니다

a를 넣던 가를 넣던. 이분은 wchar_t 가 무슨 타입인지도 잘 모르신채 글을 쓰고 있는 듯

아무래도 저랑은 의사소통이 잘 안 되는 듯합니다. 저보다는 더 믿음이 가실 스택오버플로우와 그 계열사 글 두 개 링크거는 것으로 저는 마무리하겠습니다.

익명 사용자의 이미지

댓글 쭉 살펴보시면 아시겠지만 아시아권 사람들은 그렇게 생각하지 않는 사람도 많습니다. 이제껏 그렇게 길들여져 있어서 사대주의 사상에서 벗어나질 못하는 겁니다.

익명 사용자의 이미지

The GNU Unicode String Library - 1.6 The wchar_t mess (https://www.gnu.org/software/libunistring/manual/html_node/The-wchar_005ft-mess.html)

jick의 이미지

> 그리고 유니코드(UTF-16)에서 추가적으로 할당된 4-바이트로 구성된 Code Point는 평생 한 번 쓸까말까한 중요성이 없는 문자들이 대부분이기 때문에 무시해도 상관없을 정도입니다. 대부분 2 바이트며, 2바이트만으로 한국어를 모두 표현할 수 있습니다.

...그리고 어떤 사용자가 (Unicode Character 'GRINNING FACE' (U+1F600)) 같은 걸 입력하면 화면이 깨지게 되죠. 화면만 깨지면 다행이고, 어느 라이브러리에서는 제대로 4바이트에 한글자, 다른 데서는 2바이트가 한글자 이렇게 세다가 길이가 안 맞아서 프로그램이 깨질 수도 있고.

너무 본인이 경험한 것이 시대적 추세라고 과신하시는 것 같은데, UTF-8이 쓰이는 곳은 생각보다 많습니다.

(그리고 뭔가 묘하게 멀티바이트, 유니코드, UTF-8/16 등등의 개념이 혼동되어 쓰이고 있다는 느낌이...)

* 젠장, 위에 U+1F600을 진짜로 긁어서 입력했더니 KLDP는 가볍게 글을 통째로 날려먹는군요. 보세요, 이렇게 문제가 생긴단 말입니다! -_-

어떤 문자인지는: http://www.fileformat.info/info/unicode/char/1f600/index.htm

HDNua의 이미지

토론이 재밌어서 덧글 남겨놓습니다.

저는 이렇게 생각했습니다.

bxhs의 이미지

char str[] = "안녕하세요";
printf("%s", str);

문자열 배열의 초기화는 [] 안에 숫자를 안넣는답니다.
만약 넣고 싶다면..

char str[3] = {'a','a'};
이런 식으로 초기화 하는 것이죠...

이것은 C기초 문법입니다...

HDNua의 이미지

1. 문자열 초기화할 때 숫자 넣어도 됩니다. 크기만 적당하면요.
애초에 지금의 상황은 문자열의 인코딩 때문에 문자열 길이가 달라진 게 문제여서,
bxhs님의 답변은 이 상황에선 온전한 해법으로 보기 힘듭니다.

2. 아래 문장에서도 숫자 빼서 넣을 수도 있습니다.

저는 이렇게 생각했습니다.

bxhs의 이미지

문자열 배열을 문자열로 초기화할때는 숫자를 안넣는 걸로 아는데요
희한하네요

아래 문장은 숫자를 넣든 빼든 문제될것이 없는 거고요..

HDNua의 이미지

문자열의 길이를 정해주는 것보다, 컴파일러가 알아서 계산하게 하는 것이 편하기 때문에 보통 생략합니다.

저는 이렇게 생각했습니다.

익명 사용자의 이미지

그런 이유보다는 환경마다 길이가 다르게 때문에 숫자를 넣지 않습니다.

HDNua의 이미지

단순히 편한 게 이유인 줄 알았더니 그런 이유도 있군요.
좋은 정보 감사합니다.

저는 이렇게 생각했습니다.

익명 사용자의 이미지

무슨 깡으로 틀린 지식을 가지고 '기본'을 논하는지 모르겠군요.

An array of character type may be initialized by a character string literal, optionally enclosed in braces. Successive characters of the character string literal (including the terminating null character if there is room or if the array is of unknown size) initialize the elements of the array.

굳이 표준까지 안가더라도, 이런 코드 본적 없어요?

char buf[2048] = "default value";

bxhs의 이미지

헉...그게 가능하군요....

제가 아는 C에서의 초기화는 이런식으로 했거든요..

/* Example 1 */
char string1[] = "A string declared as an array.\n";

/* Example 2 */
char *string2 = "A string declared as a pointer.\n";

/* Example 3 */
char string3[30];
strcpy(string3, "A string constant copied in.\n");

char string4[5] = "abcd"; 이런 식으로는 써본적이 없어서...

오히려 제가 c기본을 모르고 있었네요.. ^^;;;;

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.