다음 문자열의 길이는? NoSyu 풀이

By | 2009/02/13

  object님이 적으신 글 중 재미있는 글이 있었습니다.

   1: int a = strlen("123");
   2: int b = strlen("123\0");
   3: int c = strlen("123\012");
   4: int d = strlen("123\0123");
   5: int e = strlen("123\0123\0ABC");
   6: int f = strlen("123\0ABC");

다음 문자열의 길이는?

  저는 답을 맞추지 못했고, 다른 분들이 8진수이기 때문이라고 하셔서 그 이유가 맞다고 생각하였습니다. 하지만 8진수라는 이유로 찬찬히 추론해나가다 네 번째 코드를 살펴보면서 그 의문점을 가졌습니다.

  네 번째 코드에서 123이 각각 한 바이트씩 인식이 된 후 \0이 0으로 바뀌고 나서 이것이 다시 8진수를 나타내는 접두어인 0으로 인식 후 8진수 123으로 해석한다는 가정을 하였습니다. 그런데 문제점이 발생한 것입니다. 8진수 123은 10진수로 83이고 이것을 ASCII로 해석하면 ‘S’가 됩니다. 과연 이렇게 되는 것인가 궁금하였기에 코드 작성 후 어셈블리어로 살펴보았습니다.

c5

   1: int main(void)
   2: {
   3: char *a = "123";
   4: char *b = "123\0";
   5: char *c = "123\012";
   6: char *d = "123\0123";
   7: char *e = "123\0123\0ABC";
   8: char *f = "123\0ABC";
   9:  
  10: char *g = "123\12234";
  11: }

위와 같은 test 코드를 작성한 후 gcc로 어셈블리 코드를 만들게 하였습니다. g는 테스트를 위해 새롭게 추가한 것입니다.

   1: .file    "test.c"
   2: .section    .rodata
   3: :
   4: .string    "123"
   5: :
   6: .string    "123"
   7: .string    ""
   8: :
   9: .string    "123\n"
  10: :
  11: .string    "123\n3"
  12: :
  13: .string    "123\n3"
  14: .string    "ABC"
  15: :
  16: .string    "123"
  17: .string    "ABC"
  18: :
  19: .string    "123R34"
  20: .text
  21: bl main
  22: .type    main, @function
  23: :
  24: 2:
  25: pushq    %rbp
  26: I0:
  27: movq    %rsp, %rbp
  28: I1:
  29: movq    $.LC0, -56(%rbp)
  30: movq    $.LC1, -48(%rbp)
  31: movq    $.LC2, -40(%rbp)
  32: movq    $.LC3, -32(%rbp)
  33: movq    $.LC4, -24(%rbp)
  34: movq    $.LC5, -16(%rbp)
  35: movq    $.LC6, -8(%rbp)
  36: leave
  37: ret
  38: 2:
  39: .size    main, .-main
  40: .section    .eh_frame,"a",@progbits
  41: ame1:
  42: .long    .LECIE1-.LSCIE1
  43: IE1:
  44: .long    0x0
  45: .byte    0x1
  46: .string    "zR"
  47: .uleb128 0x1
  48: .sleb128 -8
  49: .byte    0x10
  50: .uleb128 0x1
  51: .byte    0x3
  52: .byte    0xc
  53: .uleb128 0x7
  54: .uleb128 0x8
  55: .byte    0x90
  56: .uleb128 0x1
  57: .align 8
  58: IE1:
  59: DE1:
  60: .long    .LEFDE1-.LASFDE1
  61: FDE1:
  62: .long    .LASFDE1-.Lframe1
  63: .long    .LFB2
  64: .long    .LFE2-.LFB2
  65: .uleb128 0x0
  66: .byte    0x4
  67: .long    .LCFI0-.LFB2
  68: .byte    0xe
  69: .uleb128 0x10
  70: .byte    0x86
  71: .uleb128 0x2
  72: .byte    0x4
  73: .long    .LCFI1-.LCFI0
  74: .byte    0xd
  75: .uleb128 0x6
  76: .align 8
  77: DE1:
  78: .ident    "GCC: (GNU) 4.3.0 20080428 (Red Hat 4.3.0-8)"
  79: .section    .note.GNU-stack,"",@progbits

c6

  .LC0, .LC1, .LC2 차례대로 각각 변수 a, b, c씩 연결됩니다. 즉, .LC0는 a의 문자열을 뜻하는 것이지요. (혹시 아니라면 낭패… 어셈블리 코드를 작년 1학기 시스템 프로그래밍 시간에 배운 것이 마지막으로 본 것인지라…;;;)

  그렇다면 a는 “123”을 가지고 b는 “123”과 “”을 가집니다. 이는 끝에 \0은 null byte를 나타내는 C Escape Sequence이기에 문자열의 끝을 나타내는 0과 동일하게 인식됩니다. 그래서 문자열 길이로 둘 다 3이 나옵니다.

  다음으로 c는 “123\n”이 d는 “123\n3″가 나옵니다. 왜 이런 식으로 나오게 되는지 잘 모르겠습니다. 다만, 이렇게 해석되지 않을까 생각합니다.

  123 이후 나오는 \012는 문자열이 아닌 값(숫자)로 바뀌게 되고 8진수로 12를 가지는 ASCII 문자인 (nl)이 되어 최종적으로 \n이 된다고 생각합니다. 그럼 왜 d는 “S”가 아닌 “\n3″가 나오냐 하면 C에서 \ 이후 숫자 3개만 읽도록 약속되어진 듯싶습니다.

  그것을 유추한 것이 g입니다. g는 “123R34″로 나오는데 이는 8진수로 122가 ASCII 문자로 R이 되기 때문입니다. 이렇게 예상은 하였으나 이상한 점은 \뒤에 0이 붙지 않았음에도 왜 8진수로 해석하느냐 하는 것입니다. 사실 저는 10진수 122인 z가 나오기를 바랬으나 R이 나왔고, 이 점이 황당해서 살펴보니 8진수 0122가 R이라는 것을 확인한 것입니다.

  나머지 e, f를 통해서 \이후 숫자만 값으로 바꿔 준다는 것을 확인할 수 있었습니다. 너무 당연한가요?^^;;

  이렇게 해석을 내리기는 하였지만 사실 C에 대해 잘 모르는 저로서는 저 해석이 맞는지 모르겠습니다.

  • \ 이후 숫자 3개까지만 받아들여 ASCII 값으로 대체한다.
  • 받아들인 숫자는 8진수로 해석한다.

이 가정이 맞는 것인지 모르겠습니다.

  다음 달이면 ‘오토마타 이론’과 ‘컴파일러’ 수업을 들어야 하는데, C 기본에서도 막히고 있으니 갑갑하네요. 먼산을 바라보고 싶지만 보이는 것은 기숙사 건물 뿐이니 좌절하고 있습니다.OTL..

PS

틀린 점, 잘못된 점 있으면 지적 부탁 드립니다.

추가로 적을 글

c10

 c11

  8진수라는 생각에 혹시 ASCII 코드표를 넘어가는 숫자이거나 숫자 9를 넣을 경우 어떻게 되는가 궁금하여 만들었습니다. 모두 범위에 벗어날 경우 i와 j 모두 \과 8진수 숫자로 바꾼 후 그 값이 문자열로 그대로 나타났습니다. 특히 j의 경우 뒤에 9는 문자와 같이 처리하여 \1이 \001로 바뀌어 나타났습니다. 이로서 확실히 8진수로 처리한다는 것을 알 수 있었습니다. 그렇다면 왜 8진수인지는 검색하면 나올 듯싶으나 후에 찾아보겠습니다. (지금 너무 피곤해서…ㅜ)

참조

동작환경 : AMD 64bit CPU, Fedora 9, gcc version 4.3.0 20080428 (Red Hat 4.3.0-8)

6 thoughts on “다음 문자열의 길이는? NoSyu 풀이

  1. Jhsieben

    어셈블리까지… (전 다룰줄 몰라서 흑흑)

    이미 찾으셨을 가능성이 많지만, 혹시나 해서 남겨봅니다.
    MSDN에서 찾은 C References 에서는, \ooo 를 ASCII 문자, octal notation 이라고 정의되어 있었습니다. (http://msdn.microsoft.com/ko-kr/library/6aw8xdf2.aspx)
    즉 \뒤의 붙은 0~7사이의 숫자 세 자리는 무조건 8진수 처리 한다는 거네요…
    \012 = \12 나 마찬가지 인거구요. 그러니까 nosyu 님이 세우신 가정이 정확한 거였어요;

    아무튼 글 잘 읽었습니다~ 즐거운 하루 되세요.

    덧. Textcube를 사용하시는것 같은데 소스 하이라이트는 어떤걸 쓰신건가요…
    제건 너무 느려서 X(

    Reply
    1. NoSyu

      반갑습니다.
      저도 어셈블리는 잘 모릅니다.OTL….
      이번에 ‘컴퓨터 구조’라는 수업을 듣는데 과연 제대로 할 수 있을지 걱정이 태산…

      그러고보니 MSDN에도 잘 정리되어있군요.^^
      object님 블로그에 달린 트랙백에 C99 문서를 찾아보신 분이 계셔서 알 수 있었습니다.
      다시 한 번 상기시켜주셔서 고맙습니다.ㅜ

      저는 Windows Live Writer를 사용하기에 거기에 있는 Plugin을 이용하고 있습니다.
      좋은지는 모르겠지만, 해당 프로그램으로 글을 쓰는지라 거기에 있는 Plugin을 이용하는 것이 저에게는 편한지라…^^;;;;

      Reply
  2. Jhsieben

    Windows Live Writer 라는게 있었군요…
    블로그는 시작한지 얼마 안되서 이것 저것 사용해보며 놀라고 있습니다 ^^;;;
    텍스트 큐브 에디터는 뭔가 부족하다는 느낌을 계속 지울 수가 없었는데…

    고민해볼 문제네요. Windows Live Writer에 소스 표기 Plugin이 있다는 말씀이군요.
    도움이 되었습니다! 감사합니다 ^^

    +. RSS 구독 들어갑니다… 나중에 귀찮게 해드릴지도 몰라요…
    ++. 혹시 RSS 구독기를 따로 쓰시는것도 있나요…? 전 그냥 텍스트큐브 관리자 구독기로 보는데 이미지가 표시가 안되서… ㅠ

    Reply
    1. NoSyu

      네.. 해당 프로그램이 블로그 포스팅 전문 프로그램답게 편한 점이 많습니다.^^ 아무래도 로컬에 내용을 저장할 수 있다는 장점이 가장 크다고 생각합니다. 아무리 저장 기능을 잘 해두어도 텍큐의 에디터는 네트워크 상에 저장되기에 손실률이 로컬보다 높죠.;; 그런 이유로 사용하고 있습니다.

      플러그인을 찾으시면 여러 사람들이 만든 것이 있습니다. 그것을 이용하시면 됩니다.^^

      귀찮게 하신다니…ㄷㄷ
      전 한RSS를 사용합니다. 아무래도 서버에 저장되어 있으니 어느 컴퓨터에서나 접근할 수 있다는 장점이 있더군요. 한국 서버라 속도도 괜찮고…^^
      참고로 제 서버는 독립계정인지라 그림 파일이 블로그 안으로 들어와야지만이 로드되도록 하였습니다. 따라서 RSS로 읽으시면 그림은 보이지 않으실 것입니다. 트래픽이 하루 2기가이고 언제나 넘치지만, 혹시나 하는 생각에 그렇게 막아놓았으니 양해 부탁드립니다. 대신 전체 공개로 하였으니 텍스트는 굳이 들어오지 않아도 읽으실 수 있습니다.^^

      Reply
  3. Jhsieben

    자세히 설명해주셔서 감사합니다 :)
    즐거운 하루되세요!

    Reply
    1. NoSyu

      감사 댓글 고맙습니다.ㅜ
      조금이나마 도움 되셨기를 바랍니다.^^
      Jhsieben 님도 좋은 하루 보내세요~^^

      Reply

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.