내가 firmware 개발을 처음 했을때 sizeof 연산자에 대해 잘못 알고 사용하여
디버깅을 했던 케이스가 생각나 이 포스팅을 하게 되었다.
sizeof에 대해 제대로 알고 있는지 스스로 한번 점검해보는 기회가 되면 좋을 것 같다.
1. sizeof 의 정체
1
2
3
4
|
int a;
printf("%d\n", sizeof(a));
printf("%d\n", sizeof a);
|
cs |
sizeof를 함수로 잘못 알고 쓰는 사람들이 꽤 많다. 위의 코드에서 sizeof(a)로 사용하는 케이스가 많다보니
기존 코드를 재사용하여 습관적으로 사용하는 사람들은 라이브러리 함수로 오해를 한다.
그러나 sizeof는 ++ -- * 등과 같은 연산자이기 때문에 연산자 우선순위의 법칙에 영향을 받고
위 코드와 같이 ( )사이에 쓰거나 한칸 띄고 크기를 재고자 하는 변수를 넣어줘도 정상 동작한다.
2. sizeof 주의사항
sizeof를 사용할 땐 몇가지 중요한 주의사항이 있다. 먼저 아래 코드를 살펴보자.
1
2
3
4
5
6
7
8
9
10
|
int get_size(char arr[]){
return sizeof(arr);
}
int main(void){
char a[10];
printf("size : %d\n", sizeof(a));
printf("size : %d\n", get_size(a));
return 0;
}
|
cs |
이 코드의 결과는 10 4이다. 10 10이라고 생각한 사람이 꽤 있을 수 있다.
sizeof 연산자는 해당 변수의 크기를 재주는 특성이 있는데 배열은 배열의 사이즈, 포인터는 포인터 변수의 크기를 반환한다. 즉 sizeof(a)는 10칸짜리 char이므로 10byte, get_size를 통해 넘겨받은 sizeof(arr)은 arr은 포인터 변수이므로 4byte이다.
a배열의 주소를 넘겨줬으니 arr이 a와 같은 것이 아니냐? 정답은 아닙니다 이다.
C언어를 처음 배울때 함수의 인자로 전달되는 것은 call by value, 주소로 전달하는 것은 call by reference로 배웠을 것이다. 이것의 정확한 의미는 변수는 같은 크기의 변수로 값이 복사되어 넘어가는 것이고, 포인터는 같은 크기의 포인터 변수로 포인터 값이 복사되어 넘어가는 것이다. 즉 a와 arr은 정확히 같지 않다. *a와 *arr은 정확히 동일하다.
그리고 한가지 더 이유가 있다.
C표준에 의하면 함수의 인자에는 배열과 함수를 넣을 수 없다고 나와 있다.
배열과 함수를 넘겨주기 위해서 포인터가 존재한다. 다만, 배열의 경우 코드 가독성을 위해 위처럼 char arr[]를 허용한다.
마지막으로 sizeof를 반드시 사용해야 하는 케이스 하나만 얘기하고 마치려 한다.
1
2
3
4
5
6
7
8
9
10
11
|
typedef struct{
int a;
char c;
float f[2];
}DATA;
int main(void){
printf("DATA size : %d\n", sizeof(DATA));
return 0;
}
|
cs |
구조체는 pack 옵션에 따라 시스템의 설정에 따라 크기가 달라질 수 있기 때문에 반드시 sizeof로 크기를 재야 한다.
한번에 너무 많은 얘기를 하면 지루할 수 있으니 이 포스팅은 여기까지 ㅎㅎ
'C언어' 카테고리의 다른 글
[C 언어] 데이터 타입의 형 변환 (2) (0) | 2023.01.20 |
---|---|
[C 언어] 데이터 타입 2번째 (0) | 2023.01.14 |
[C 언어] [배열] 배열 기초 (0) | 2023.01.13 |
[C언어] 데이터 타입 / 형 변환 (0) | 2023.01.10 |
[C 언어] printf 파헤치기 (0) | 2023.01.08 |