cfaq 10

Cfaq 11

Q 11.11 다음과 같은 선언에서: typedef char *charp; const charp p; 왜 p가 가리키는 char가 const가 되지 않고, p 자체가 const가 되는 것 일까요? Answer Typedef로 치환한 것은 순수하게 textual 치환이 아닙니다. (이 것은 typedef를 쓰는 한가지 장점이기도 합니다; 질문 1.13 참고) 다음과 같은 선언 에서: const charp p; const int i가 i를 const로 만드는 것과 같은 원리에서, p는 const가 됩니다. p에 대한 선언은, 포인터가 관련이 되어있는지 typedef 안까지 쫓 아가서 확인하지 않습니다. Note 아래와 같은 선언이 있다고 가정하고 (질문 11.9 참고): int * const const_po..

Cfaq 9

Q 11.18 메시지 “warning: macro replacement within a string literal”은 무슨 뜻 이죠? Answer : ANSI 이전의 어떤 컴파일러/전처리기는 매크로 정의를 다음과 같이 정 의할 경우: #define TRACE(var, fmt) printf("TRACE: var = fmt\n", var) 다음과 같은 식으로 호출하게 되면: CHAPTER 11. ANSI/ISO STANDARD C 193 TRACE(i, %d); 다음과 같이 확장하게 됩니다: printf("TRACE: i = %d\n", i); 즉, 매크로 인자로 나온 이름이 문자열 안에 있는 경우라도 확장시켜 버립 니다. (물론 이러한 버그가 위와 같이 유용하게 쓰일 수도 있지만, 이 것은 대개 초창기 컴..

cfaq 8

Q 10.4 여러 문장으로 이루어진 매크로를 만드는 좋은 방법 좀 알려 주세요. Answer 이런 매크로를 만드는 일반적인 방법은 매크로 자체를 일반 함수처럼 쓸 수 있도록 하는 것입니다. 즉 호출하는 쪽에서 마지막 ‘;’을 직접 써 주게 하고 매크로의 몸통에서는 ‘;’을 따로 써 주지 않는 식으로 쓰는 것입니다. 예를 들면: MACRO(arg1, arg2); 그러므로 매크로 정의는 단순히 여러 statement를 중괄호로 둘러싼 ‘compound statement’ 형식으로 만들 수 없습니다. 왜냐하면 이 매크로가 호 출될 때 세미콜론이 추가적으로 붙는다면 if나 if/else 문장에서 에러가 발생할 수 있기 때문입니다. 다음 코드를 보기 바랍니다: if (cond) MACRO(arg1, arg2); ..

Cfaq7

Q 8.9 제 컴파일러에 버그가 있습니다. sizeof('a')의 값이 sizeof(char)인 1 로 나오지 않고, 2가 나옵니다. Answer 놀랍게도, C 언어에서 문자 상수(character constant)의 타입은 int입니 다. 따라서 sizeof('a')는 sizeof(int)와 같습니다. (C++에서는 조금 다릅니다.) 덧붙여 질문 7.8도 참고하시기 바랍니다. Note 참고로 C++에서 문자 상수의 타입은 char입니다. 즉, sizeof('a')는 sizeof(char)와 같습니다. Q 10.1 다음과 같이 간단한, 함수와 비슷한 매크로를 만들려고 합니다. #define square(x) x * x 그런데, 가끔씩 제대로 동작하지 않습니다. 왜 그럴까요? Answer 매크로 확장(ex..

Cfaq 6

Q 7.29 (질문 6.14를 따라서) 배열을 동적으로 할당한 다음, 이 배열의 크기를 바꿀 수 있을까요? Answer 물론입니다. realloc이 바로 그 역할을 해 주는 함수입니다. (예를 들어, 질문 6.14에 나온 것처럼 dynarray) 동적으로 할당된 배열의 크기를 바꾸 려면 다음과 같은 코드를 씁니다: dynarray = (int *)realloc((void *)dynarray, 20 * sizeof(int)); realloc이 항상 메모리 블럭의 크기를 늘리는데 쓰이는 것은 아닙니다. realloc은, 가능하면, 전달받은 인자와 같은 포인터 값을 돌려주지만, 요 청한 크기에 맞게 메모리 블럭을 다시 찾을 경우에는, 인자로 전달된 포인 터 값과는 다른 값을 돌려줍니다. 이 경우, 인자로 전달..

Cfaq5

Q 6.20 정적 또는 동적으로 할당된 다차원 배열을 함수에 전달할때, 서로 구별하지 않고 쓸 수 있는 방법이 있을까요? Answer 완벽한 방법은 없습니다. 다음 선언이 있다고 할 때: int array[NROWS][NCOLUMNS]; int **array1; /* ragged */ int **array2; /* contiguous */ int *array3; /* "flattened" */ int (*array4)[NCOLUMNS]; int (*array5)[NROWS][NCOLUMNS] 포인터들은 질문 6.16에 나온 것처럼 초기화되어 있다고 가정하고 함수 선 언은 다음과 같다고 가정합니다: void f1a(int a[][NCOLUMNS], int nrows, int ncolumns); void f..

Cfaq3

Q 4.12 함수를 호출할 때, 포인터를 써서 호출하는 방식을 봤습니다. 왜 이런 일을 하는 거죠? Answer 원래, 함수를 가리키는 포인터는 * 연산자를 쓸 경우 (그리고 우선 순위를 위해 괄호를 같이 쓸 경우) 진짜(real) 함수 호출로 변경됩니다: int r, func(), (*fp)() = func; r = (*fp)(); 위 코드의 마지막 줄의 의미는 다음과 같습니다: fp는 함수를 가리키는 포 인터이고, *fp는 이 함수를 뜻합니다. 그리고 뒤따르는 ()는 함수 호출에 서 쓰이는 인자를 받는 인자 list입니다. 이때 연산자 우선 순위를 고려해서 *fp를 괄호로 둘러쌉니다. 이러면 완벽한 함수 호출이 됩니다. 다음과 같은 이론도 있습니다: 함수는 항상 포인터를 써서 불려지고, 수식 에서 “..

Cfaq 2

은근히 이게 항상 헤갈린다.. + Q 4.3 ‘*p++’은 ‘p’를 증가시키는 것인가요, 아니면, ‘p’가 가리키는 것을 증가시 키는 것인가요? Answer *, ++, --와 같은, 피연산자가 하나인 연산자는 (unary operator라고 합니 다.) 항상 오른쪽에서 왼쪽으로 결합합니다. 따라서 *p++는 *(p++)와 같 습니다; 일단 p를 증가시킨 다음, p가 증가하기 전에 가리키던 곳의 값을 리턴합니다. p가 가리키는 것을 증가시키려면 (*p)++을 (또는, 부작용이 일어나도 상관없는 경우, ++*p를 써도 됩니다) 쓰면 됩니다. Q 16.7 External structure를 푸는 코드를 받았습니다만, 실행하면 항상 “unaligned access”라는 에러가 납니다. 이게 무슨 뜻인가요? 실..

Cfaq 1

(d != 0 && n / d > 0) 위와 같이 사용하면 숫자가 0으로 나눠지는 것을 방지 할 수 있다! 흠.. 신기하군.. + Q 3.6 조건에 따라서 &&, || 연산자의 오른쪽이 평가되지 않는다고 보장할 수 있 나요? Answer 보장합니다. if (d != 0 && n / d > 0) { /* average is greater than 0 */ } 이나, if (p == NULL || *p == '\0') { /* no string */ } 는 C 코드에서 매우 자주 볼 수 있는 것입니다. 이는 이른바 ‘short circuit’ 이라고 합니다. 만약 이 ‘short circuit’이 없다면, 첫번째 예제의 &&의 오 른쪽에서, d가 0일 경우, 0으로 나누는, ‘divide by 0’ 에러가 ..