Post

(C) 타입 Types / Type Casting / 가변 인자

<stdint.h>를 사용하도록 하자. int보다 uint8\_t 같은 고정 크기 타입을 사용하는 것이 좋다. char보다 TCHAR를 사용하는 것이 좋다. 윈도우인 경우 컴파일 옵션에 따라 리눅스 등에서도 호환 가능하기 때문.

Types

1
2
uintptr\_t

포인터를 대상으로 덧셈, XOR 등 수치 연산이 필요한 경우 포인터를 숫자값으로 취급하기 위해 사용하는 타입. 어떤 포인터라도 담을 수 있는 크기의 데이터 타입이라는 의미가 된다. 따라서 포인터를 대상으로 수치 연산이 필요한 경우 사용한다. (uintptr\_t)this + 4이렇게 더하기 연산을 해도 1씩 증가하기 때문에, ` uint8_t*같은 것으로 변환하는 것 보다 더 낫다. uint8_t*로 변환하면 + 같은건 되는데 % / *` 연산자에서 에러난다.

1
2
(void \*)

단순히 어떤 것을 가리키는 포인터 일 경우 사용한다. uintptr\_t와 달리 원래의 type으로 다시 cast했을 때 제대로 동작함을 보장해준다.

1
2
size\_t

배열 선언 시 할당할 수 있는 원소 수의 최댓값을 의미한다. 따라서 배열 원소 수의 최댓값에 사용한다.

Type Casting

타입 캐스팅을 적절히 해주지 않으면 계산에서 오류가 발생한다. 특히 포인터가 그렇다. printf()할 때도 마찬가지.

source :

1
2
3
4
chunk0\_ptr[1] = (uint64\_t) &chunk0\_ptr - (3\*sizeof(uint64\_t));
printf("chunk0\_ptr[1] : %p / &chunk0\_ptr - 3 : %p\n",
chunk0\_ptr[1], &chunk0\_ptr - (3\*sizeof(uint64\_t)));

result :

1
2
3
chunk0\_ptr[1] : 0x602050 / &chunk0\_ptr - (3\*sizeof(uint64\_t)) : 0x601fa8

이런 식으로 대입할 때와 같은 값을 출력하도록 했는데 다른 값이 출력되는 이유는, &chunk0\_ptr 은 주소이므로 -1c -8 이 되기 때문. ( 64bit OS ) 따라서 - (3\*sizeof(uint64\_t)) ==> - 8\*(3\*sizeof(uint64\_t)) 이 되어버린다.

이를 방지하려면 대입할 때와 동일하게 형변환을 해주거나, 형변환을 하지 않으려면 -3만 빼주어야 한다.

1
2
3
4
chunk0\_ptr[1] : 0x602050 / (uint64\_t) &chunk0\_ptr - 3\*(sizeof(uint64\_t)) : 0x602050
chunk0\_ptr[1] : 0x602050 / &chunk0\_ptr - 3 : 0x602050

~0u

~(uint)0과 같다. 따라서 0xffffffff가 된다.

가변 인자
1
2
3
#include <stdarg.h>
int \_\_printf (const char \*format, ...)

  • 가변 인자 함수를 만들기 위해서는 stdarg.h가 필요하다.
  • 반드시 1개 이상의 고정 파라미터가 있어야 한다.
  • ...은 파라미터 가장 뒤에 위치해야 한다. 대충 이런 식으로 동작한다.
1
2
3
4
5
6
int va\_func(int args, ...) {
va\_list ap;
va\_start(ap, args);    // ap가 가변 인자 리스트를 가리키도록 대입.
int arg = va\_arg(ap, int);
va\_end(ap);

const

파라미터로 받는 변수가 실제로는 상수가 아니지만, 함수 내부에서 변경하지 못하도록 설정하고 싶은 경우 const를 활용할 수 있다.

1
2
3
4
int f(const int a){
a = 3; // compile time error
}

const type *ptr / type * const ptr
1
2
3
4
5
6
int a = 3;
int b = 5;
const int \*ptr = &a;
ptr = &b;    // right
\*ptr = 10;    // error

const int를 가리키는 포인터. 따라서 \*ptr을 수정할 수 없다. 이 때 가리키고 있는 대상이 const가 아니어도, ptr로 접근하는 경우는 수정 불가능하다.

1
2
3
4
5
6
int a = 3;
int b = 5;
int \* const ptr = &a;
ptr = &b;    // error
\*ptr = 10;    // right

int \*를 가리키는 const포인터. 따라서 c ptr을 수정할 수 없다.

This post is licensed under CC BY 4.0 by the author.