Skip to content

[C] Deep C

Myungchul Shin edited this page Feb 24, 2015 · 10 revisions

  • question 1
int main()
{
    int a = 42;
    printf("%d\n",a);
}
  • answer 1
    • '#include <stdio.h>'가 없어도 C 컴파일러는 compile,link 가능. 하지만 C++의 경우는 모든 함수에 대한 명시적 원형을 요구하기 때문에 reject
    • C 컴파일러는 묵시적으로 printf()를 선언해서 끼워넣는데, standard library와 링킹할때 printf를 찾고 그 이름이 같기 때문에 실행가능한 것이다.
    • 물론 warning이 있을 수 있음
    gcc 4.4.6
    test.c: In function ‘main’:
    test.c:4: warning: implicit declaration of function ‘printf’
    test.c:4: warning: incompatible implicit declaration of built-in function ‘printf’
    test.c:5: warning: control reaches end of non-void function
    • return 값이 명시적으로 존재하지 않지만, C99의 경우 보통 runtime environment에서 'success'를 표시하는 값으로 리턴. ANSI C의 경우는 undefined. 보통 return은 register에 있는 값을 리턴하는데, printf의 리턴값은 화면에 찍은 문자의 개수이므로 register에 '3'이 남고 이것이 리턴되도 놀랄일은 아니다. (하지만, 현재 gcc 버전으로 -std=c89로 컴파일해도 리턴값이 3이 되는 것을 보기는 힘들다)
    printf("%d\n",printf("%d\n",a));
    • 'int main()'은 'int main(void)'로 기술하는 것이 standard(즉, argument가 없음). 'int main()'은 몇개의 argument가 와도 상관없다는 의미. 하지만, 큰 문제는 없다.

  • question 2
#include <stdio.h>
void foo(void)
{
    static int a = 3;
    ++a;
    printf("%d\n",a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
  • answer 2
    • '4,5,6'
    • function 내부의 static variable 'a'는 딱 한번 초기화된다(initialized). 따라서, 해당 이름으로 다시 참조되는 경우, 이전에 할당된 값이 있으므로 그것을 1 증가시킴. 또한 'a'의 scope는 foo()의 내부로 한정된다. main()에서는 볼 수 없음.

  • question 3
#include <stdio.h>
void foo(void)
{
    static int a;
    ++a;
    printf("%d\n",a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
  • answer 3
    • '1,2,3'
    • static variable은 0으로 초기화된다.(딱 한번이지만)

  • question 4
#include <stdio.h>
void foo(void)
{
    int a;
    ++a;
    printf("%d\n",a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
  • answer 4
    • 'three consecutive values', ex) '1 2 3'
    • stack에 할당될때 동일한 memory location일 가능성이 크다. 따라서, 최초 0인 경우 처음 foo()에서 1, 다음 호출에서 같은 메모리 위치를 잡으면 garbage value인 '1'을 1 증가시켜서 '2'가 나오고, 그 다음 '3'이 나옴(optimization 옵션을 주고 컴파일하면 달라짐)
    • auto variable이 초기화 되지 않은 이유는 단순히 속도를 빠르게하는 최적화 컨셉이 녹아있는 것일 뿐.

  • question 5
#include <stdio.h>

static int a;

void foo(void)
{
    ++a;
    printf("%d\n",a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
  • answer 5
    • '1 2 3'
    • 1번만 초기화되고 그 값이 0이므로
    • 'static'은 여기서 scope가 현재 파일에서만 가능하다는 것을 명시한다. 외부 파일에서는 참조할 수 없음.

  • question 6
#include <stdio.h>

int a;

void foo(void)
{
    ++a;
    printf("%d\n",a);
}

int main(void)
{
    foo();
    foo();
    foo();
}
  • answer 6
    • '1 2 3'
    • global variable은 0으로 초기화된다.(static과 무관하게)
    • static을 제거했으므로, scope는 현재 파일을 포함해서 다른 파일도 접근가능하다.(linker visibility)

  • question 7
#include <stdio.h>

void foo(void)
{
    int a;
    printf("%d\n",a);
}

void bar(void)
{
    int a = 42;
}

int main(void)
{
    bar();
    foo();
}

$ cc test.c && ./a.out
$ 42

why?
  • answer 7
    • 컴파일러는 name pool을 가지고 있는데, bar()에 의해서 할당된 'a'가 foo()에서도 사용하면 재사용한다. 만약, 이름을 'b'로 바꾸면 결과가 다를 것임
    • optimize 옵션을 주는 경우는 garbage

  • question 8
#include <stdio.h>

void foo(void)
{
    int a = 41;
    a = a++;
    printf("%d\n",a);
}

int main(void)
{
    foo();
}
  • answer 8
    • 'undefined'
    • cc -Wall test.c && ./a.out
    test.c:6: warning: operation on ‘a’ may be undefined
    
    • C의 규칙중 하나는 sequence point 사이에서 variable의 update는 반드시 1번만 있어야 한다는 것(rule for sequencing)
    • sequence points

  • question 9
#include <stdio.h>

int b(void) { puts("3"); return 3; }
int c(void) { puts("4"); return 4; }

int main(void)
{
    int a = b() + c();
    printf("%d\n",a);
}
  • answer 9
    • evaluation order is 'unspecified' not 'undefined'
    • 컴파일러는 evaluation order를 최적화 관점에서 선택한다. 따라서 '3 4 7' or '4 3 7'
Clone this wiki locally