알라딘서재

누리로
  • 모던 C
  • 옌스 구스테트
  • 27,000원 (10%1,500)
  • 2022-01-14
  • : 207

앞부분만 조금 읽어보았는데, 맥락상 꼭 있어야 할 설명이 생략되어 있어서 당황스러웠다.


이를테면 89쪽에서 표현식 

-1L < 0U

의 결과값은

- "UINT_MAX <= LONG_MAX인 플랫폼에서는 0U가 0L로 변환"되어 "true가 된다"

- "LONG_MAX < UINT_MAX인 플랫폼에서는 -1L이 -1U(즉, UINT_MAX)로 변환되어" "false가 된다"

고 설명하고 있다.


이 설명의 내용이 틀린 것은 아니지만, 왜 그렇게 되는지에 대한 설명이 책에 없다는 게 문제다.

저렇게 변환되는 까닭은 C 표준에서 규정하고 있는 usual arithmetic conversion 룰 때문인데, 만일 usual arithmetic conversion 에 대한 개념이 없는 상태에서 위 서술된 내용을 먼저 접하게 된다면 그저 혼란만 가중될 것이다.

지면관계상 usual arithmetic conversion 의 내용을 설명하지 않았다 하더라도, 저 부분에서 최소한 usual arithmetic conversion 이라는 키워드는 언급하고 넘어갔어야 했다.



그밖에도 틀린 서술이나 이상한 표현이 꽤 눈에 띈다.


1)

88쪽 밑에서 세번째 줄에 표현식

-1U < 0U

의 값이 '참'(true)이라고 나와 있는데, 그렇지 않다.

-1U는 UINT_MAX 와 완전히 같고, UINT_MAX > 0U 이므로 -1U > 0U가 성립한다. 따라서 위 표현식의 값은 false이다.


2)

87쪽에서 "이번에도 signed int의 최솟값과 최댓값이 각각 -2147483648과 2147483648이라고 가정했다고"고 나와 있는데, 우선 이 책의 앞에서 그렇게 가정한 적이 없다.

또한 저렇게 가정하면, 0x80000000은 signed int로 표현할 수 '있는' 값이 되므로 그 아래에 나와있는

signed int c = 0x80000000;  // 위험: 지정된 타입을 벗어나는 값이다

의 주석은 틀린 설명이 된다.

signed int의 최댓값이 2147483647이라고 가정해야 위 주석이 맞는 설명이 된다.

실제로도, 대부분의 (사실상 '전부'라고 해도 무방할 듯) 32비트와 64비트 플랫폼에서 INT_MAX는 2147483647 (즉, 2^31 - 1)로 정의된다.


3)

85쪽 위에서 두번째 줄에

"0에 대한 정수형 소수점 표현은 없다"

고 서술되어 있다.

이게 도대체 무슨 말일지 생각해 봤는데, 나는 이것이 오역일 것이라고 확신한다.

원문을 보지는 못했지만, 아마도 원문에는 decimal integer representation 이라고 서술되어 있을 것이다.

만일 그렇다면, 여기서 decimal은 그 앞에 서술된 문맥과 c언어에 대한 배경 지식을 고려하여 '10진수의'라는 뜻으로 해석해야 한다. '소수의'라는 뜻으로 해석하는 것은 명백한 오역이다.

참고로 c언어에서 0은 '8진수' 정수로 표현된 상수이다. (10진수 아님)

0 : 8진수 정수표현

0x0 : 16진수 정수표현

'\0' : 문자 상수 표현 (참고로 c언어에서 문자 상수의 타입은 int 이다. char 아님.)



이상과 같이 몇 페이지 안 되는 분량에서 다수의 틀린 내용과 불충분하게 설명된 서술을 마주하고 나니, 책을 계속 읽기가 두려워진다.

조금이라도 이해가 안 되거나 의심이 가는 내용은 Google / Stack Overflow 검색 혹은 C 표준 문서에서 관련된 부분을 찾아서 일일히 교차 검증을 해 가면서 읽어야 할 책이다.



추가) 그리고 이 책만의 문재는 아니지만, '수'라는 단어를 써야 할 상황에서 자꾸 '숫자'라는 단어를 사용하고 있어서 몰입에 방해가 된다.

'숫자'는 '수를 나타내는 데 사용하는 문자'를 뜻하는 말이기 때문에 '수'와 '숫자'는 구별해서 사용해야 한다.

특히, 같은 수라도 기수법(진법)이 바꾸면 그 수의 숫자 표현은 달라질 수 있음에 유의해야 한다. 이를테면 십진법으로 나타낸 수 27은 팔진법으로 나타내면 33이고 16진법으로 나타내면 1B인데 이들은 모두 같은 '수'를 나타낸 것이지만 사용된 '숫자'(들)은 전부 다르다.



추가) 165쪽 표 8-9 설명에서 '서식 지정자'(X) '서식 수정자'(O)


추가) 173쪽 strtoul.c 소스에서 오버플로우 판정 조건 (40행)이 잘못되었음.

if (ULONG_MAX / base < ret) {

위와 같이 ret가 ULONG_MAX / base 보다 클 때에만 오버플로우 처리를 하고 있는데

ret가 ULONG_MAX / base 와 같은 경우에도 c값에 따라서 오버플로우가 발생할 수 있음.

40행을 아래와 같이 고쳐야 함

if (ULONG_MAX / base < ret || ULONG_MAX / base == ret && ULONG_MAX % base < c) {



추가) 180쪽: 현재 수준에서 getenv() 함수로 할 수 있는 일은 특정한 이름의 환경 변수가 존재하는지 확인하는 정도라고 서술되어 있으나, 왜 그런지에 대한 설명이 없다.

곧바로 이어지는 내용은 getenv()보다 안전한 C11부터 추가된 getenv_s()를 이용하여 환경 변수의 값을 구하는 예제다. 이는 getenv() 함수에 문제가 있다는 것을 암시하지만, 구체적으로 무슨 문제가 있는지는 여전히 알 수 없다.


구글과 스택오버플로우에서 찾아봤는데

https://stackoverflow.com/questions/48568707/getenv-function-may-be-unsafe-really/48573082#48573082

getenv 함수를 여러 번 호출할 때 이전에 호출된 함수가 반환한 포인터의 유효성이 보장되지 않는다고 한다 (위 링크 참고)

C 표준 문서에도 이에 대한 언급이 있는 모양이다 (아래 링크 참고)

https://stackoverflow.com/questions/15034723/standard-c-usage-of-getenv-and-safe-practices#comment21136562_15034723


만일 이게 문제라면, 책에 나온 예제는 굳이 getenv_s()를 쓸 필요가 없어 보인다. getenv()를 호출하고 리턴한 포인터가 가리키는 문자열을 '곧바로' 복사해서 복사한 것만 사용한다면, 저런 문제와 마주할 일이 없다.

오히려, 예제에서 환경변수 값(문자열)의 길이를 조사하여 버퍼를 동적 할당하지 않고 길이가 256으로 고정된 버퍼에 환경변수 값을 복사하는 것이 더 위험해 보인다.

아울러, 환경변수의 값을 일회성으로 출력하는 것이 목적이라면 버퍼에 복사할 필요도 없다.  getenv()가 반환한 포인터를 그대로 printf()의 인수로 전달하면 그걸로 충분하다.


  • 댓글쓰기
  • 좋아요
  • 공유하기
  • 찜하기
로그인 l PC버전 l 전체 메뉴 l 나의 서재