포인터의 기본 문법에 대해서 조금 더 알아볼게요. 코드는 다음과 같습니다.
int i = 10;
int *p = &i;
*p = 20;
이 때 64 비트 CPU 기반으로 메모리 구조를 한번 그려볼까요?
1008번지에는 i란 지역변수가 있고 1000 번지에는 p란 포인터 타입 지역 변수가 위치해 있죠.
포인터 주소 값
| 1000 |--- 1008
| |
p | 1008 |--- (10 -> 20) i
변수 i의 위치가 1008번지라면 포인터 변수 p에는 i 변수 주소를 대입했으므로 p는 int을 가르키는 주소가 됩니다.
이 때 주소 변수를 선언하는 방법은 int *p입니다.
그런데 컴파일러는 이 선언부를 다음과 같이 해석합니다.
pointer to int
주소 변수를 가르키는 대상체의 타입이 중요하므로 위와 같이 씁니다. 이를 번역하면 int을 가르키는 주소 변수 p라고 하는 거죠.
보통 주소 변수 자체 크기는 CPU 주소 버스와 같습니다. 32비트 아키텍처에서는 4바이트죠.
이 때 포인터 입장에서는 음수를 처리할 수 없습니다. 그래서 unsigned long 으로 해석합니다. 참고로 long은
CPU 주소 버스와 크기와 같으므로 언제나 포인터 길이가 같습니다.
그럼 p 란 포인터가 1008이면 p + 1 은 얼마일까요?
정수의 덧셈이면 1008 + 1 = 1009가 되겠지만 포인터는 대상체가 무엇인지가 따라 연산이 달라집니다.
컴파일러는 선언시 대상체의 크기를 계산하거든요.
p + 1 = p + sizeof(*p) * 1;
p + 1 = p + sizeof(int) * 1;
따라서 p가 1008이면 (p + 1) 는 1012가 됩니다.
포인터 주소 값
| 1000 |--- 1008
| |
p | 1008 |--- (10 -> 20) i
| |
(p+1) | 1012 |
만약 p란 포인터 변수가 struct task_struct이고 이 구조체 사이즈가 100바이트이면
(p + 1) 연산으로 1108 바이트를 가르키겠죠.
포인터 주소 값
| 1000 |--- 1008
| |
p | 1008 |--- (10 -> 20) i
| |
| 1012 |
| |
//... | |
(p+1) | 1108 |
'Core BSP 분석 > 리눅스 커널 핵심 분석' 카테고리의 다른 글
[라즈베리파이] 비트 처리 __test_and_set_bit() __test_and_clear_bit() 함수 동작 원리 (0) | 2023.05.06 |
---|---|
[리눅스] printk 아규먼트 포멧 (0) | 2023.05.06 |
[Linux][GCC]## 매크로 - 심볼 생성 (0) | 2023.05.06 |
[Linux] 컴파일러(Complier) 소개 (0) | 2023.05.06 |
GCC - C언어 매크로(Macro) -(1) (0) | 2023.05.06 |