Skip to main content

char 타입과 EOF

요새 한참 XML parser를 만들기 위해 이것 저것 공부도 하고 코딩도 하고 있는 중입니다. 그런데 역시 아는 것과 하는 것 사이에는 많은 차이가 있군요. Devils in the details랄까요? ;-)

이번 글에서는 char 타입과 EOF에 관한 내용에 대해 생각해 볼까 합니다. 다들 아시다시피 기존의 8bits char 타입을 사용하는 C 함수들의 경우 char를 리턴하기 위해 int 타입을 사용하였습니다.


ex) int fgetc(FILE *stream);


이유는 하나, 실제 사용되는 char 값들과 EOF값을 구분하기 위해서였죠. 8bits char 타입의 값들은 char가 unsigned라고 가정하면 ((char나 wchar_t의 signed, unsigned 여부는 구현에 따라 다를 수 있습니다.)) 0~255까지의 범위안의 값들만 가질 수 있기 때문에 256부터의 값은 어떤 것이든 EOF를 나타내기 위해 사용될 수 있습니다. 일반적으로 -1, 즉 0xFFFFFFFF이 사용되죠.

그런데 이번에 XML parser를 구현하면서 평소에 잘 사용하지 않던 wchar_t 타입을 사용하다 보니 궁금한 점이 생겼습니다. Linux의 g++에서 wchar_t의 sizeof는 32bits입니다. 그렇다면 WEOF의 타입은 무엇이어야 할까요? 또 값은요. 만약 wchar_t의 값이 0~0xFFFFFFFF을 모두 사용할 수 있다고 생각한다면 ((wchar_t가 unsigned라고 가정했을 경우)) WEOF의 타입은 uint64_t 정도가 되어야 할 것입니다. 하지만 64bits int 타입을 아직 모든 컴파일러가 지원하는 것은 아니므로 문제가 될 수 있습니다.

그래서 아래와 같이 간단한 코드를 사용하여 시험해 보았습니다.


cout << sizeof(char) << ", " << sizeof(EOF) << ", " << EOF << endl;
cout << sizeof(wchar_t) << ", " << sizeof(WEOF) << ", " << WEOF << endl;

// result
// 1, 4, -1
// 4, 4, 4294967295(-1)


예상대로 WEOF의 타입은 uint32_t쯤 되는 것 같습니다. ((실제 Linux에서 헤더 파일들을 찾아 들어가보니 stream 클래스에서 사용하는 eof()의 타입은 int로 정의되어 있네요.)) 그렇다면 어떻게 32bits 타입의 EOF를 32bits char 타입에 사용할 수 있을까요? 이유는 과거에 사용되었던 문자들, 현재 사용되는 모든 문자들을 다 더해도 이렇게 많지 않다고 가정할 수 있기 때문입니다. Unicode만 해도 최대 가질 수 있는 값은 0x10FFFF까지니까 안전하게 (uint32_t) -1 값을 WEOF로 사용해도 문제가 없습니다.

아마 우주의 다른 곳에서 외계인들이 발견되고 그 외계인들에게 우리가 만든 프로그램을 팔아야 되기 전까지는 안전하게 32bits짜리 WEOF를 사용할 수 있을 것 같습니다. :-)

Comments

  1. char이 담을 수 있는 값 + EOF를 담을 수 있는 형이 int라면, wchar_t가 담을 수 있는 값 + WEOF를 담을 수 있는 형은 cwchar에 정의된 wint_t입니다. 이 자료형은 ISO C의 7.24.1절에 설명되어 있고, ISO C++에서 이를 그대로 받아들여 쓰고 있지요. :)

    ReplyDelete
  2. 아.. 그렇군요. 시험만 해볼께 아니라 문서를 찾아봤어야 했는데... :-) C99 문서의 7.24.1를 읽어보니 추측했던 내용들이 대충 맞군요.

    WEOF - which expands to a constant expression of type wint_t whose value does not correspond to any member of the extended character set.

    그리고 footnote 269, 270번을 보니 위의 시험 결과가 C99 표준을 준수하고 있다는 것을 알 수 있겠네요.

    269) wchar_t and wint_t can be the same integer type.
    270) The value of the macro WEOF may differ from that of EOF and need not be negative.

    ReplyDelete

Post a Comment

Popular posts from this blog

CodeHighlighter plugin test page.

This post is for testing CodeHighlighter plugin which uses GeSHi as a fontifier engine. ((Those code blocks are acquired from Google Code Search .)) ((For more supported languages, go CodeHighlighter plugin or GeSHi homepage.)) C++ (<pre lang="cpp" lineno="1">) class nsScannerBufferList { public: /** * Buffer objects are directly followed by a data segment. The start * of the data segment is determined by increment the |this| pointer * by 1 unit. */ class Buffer : public PRCList { public: Buffer() { ++index_; } PHP (<pre lang="php" lineno="4">) for ($i = 0; $i $value = ord( $utf8_string[ $i ] ); if ( $value < 128 ) { // ASCII $unicode .= chr($value); } else { if ( count( $values ) == 0 ) { $num_octets = ( $value } $values[] = $value; Lisp (<pre lang="lisp">) ;;; Assignment (define-caller-pattern setq ((:star var fo...

Textiler plugin test page

This post is for testing Textiler plugin . This plugin uses Textile engine (version 2.0.0). The sample text is come from Textile test page. (Note that the result will be vary according to your CSS options.) Supported wiki syntax Rendering result h2{color:green}. This is a title h3. This is a subhead p{color:red}. This is some text of dubious character. Isn't the use of "quotes" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote. bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised. Simple list: #{color:blue} one # two # three Multi-level list: # one ## aye ## bee ## see # two ## x ## y # three Mixed list: * Point one * Point two ## Step 1 ## Step 2 ## Step 3 * Point three ** Sub point 1 ** Sub point 2 Well, that went well. How about we insert an <a href="/" title="watch out">old-fashioned hypertext link</a>? Will the quo...

C++ of the Day #43 - SQLite3 C++ wrapper #1

The Definitive Guide to SQLite 를 읽다가 공부 겸 해서 C++ wrapper를 만들어 보았습니다. 최대한 C++ 냄새(?)가 나도록 만들어 보았습니다. :-) ((SQLite는 복잡한 관리가 필요없이 사용가능한, 파일이나 메모리 기반의, 라이브러리로 제공되는, 약 250kb 용량의, 대부분의 SQL92문을 지원하는, open source RDB입니다.)) 이 wrapper를 사용하기 위해서는 (당연하게도!) sqlite3 와 (당연하게도?) boost 라이브러리가 필요합니다. 사용 예들을 살펴보는 것으로 설명을 대신합니다. 이번 글에서는 다음과 같은 contacts 테이블이 test.db에 존재한다고 가정합니다. CREATE TABLE contacts ( id INTEGER PRIMARY KEY, name TEXT NOT NULL, phone TEXT NOT NULL, UNIQUE(name, phone) ); Command 먼저 test.db 파일을 사용하기 위해 다음과 같이 파일 이름을 주어 connection 객체를 생성합니다. 생성과 동시에 test.db와 연결이 이루어집니다. ((생성자외에 open() 함수를 사용할 수도 있습니다.)) sqlite3pp::connection conn("test.db"); 다음은 contacts 테이블에 정보를 추가하는 가장 간단한 방법입니다. connection 클래스에서 제공하는 execute 함수를 사용합니다. ((executef 함수를 사용하면 printf와 같은 문법을 사용하여 query문을 작성할 수 있습니다.)) conn.execute("INSERT INTO contacts (name, phone) VALUES ('user', '1234')"); 위와 동일한 작업을 parameterized query를 사용하여 할 수도 있습니다. ((step()함수가 실제 query문을 수행하는 함수입니다. ...