그라운드 임베디드 EN 유튜브 구독

노트 / C 언어

포인터: 주소를 다루면 레지스터가 보인다

포인터는 주소를 담는 변수입니다. 특정 주소를 읽고 쓰는 것이 레지스터 제어의 전부라는 점을 정리했습니다.

GROUND EMBEDDED · 정리 노트C 언어 06포인터 1uint32_t x = 10; 2uint32_t *p = &x;// x의 주소 3*p = 20;// 주소를 따라가서 값을 바꿈, 이제 x…

변수는 메모리 어딘가에 있고, 그 위치가 주소입니다. 포인터는 그 주소를 값으로 가진 변수입니다.

uint32_t x = 10;
uint32_t *p = &x;   // x의 주소
*p = 20;            // 주소를 따라가서 값을 바꿈, 이제 x는 20

레지스터 제어와의 관계

MCU의 주변장치 레지스터는 정해진 주소에 있습니다. 데이터시트에 GPIOA의 출력 레지스터가 0x40020014라고 적혀 있다면, 그 주소를 포인터로 만들어 쓰면 핀이 움직입니다.

#define GPIOA_ODR (*(volatile uint32_t *)0x40020014)
GPIOA_ODR |= (1u << 5);   // PA5 HIGH

STM32의 GPIOA->ODR 같은 표현도 결국 구조체 포인터로 이 주소를 가리키는 것입니다.

자주 하는 실수

  • 초기화하지 않은 포인터를 따라가기
  • 이미 사라진 지역 변수의 주소를 쓰기
  • 포인터 자료형 크기를 잘못 써서 옆 레지스터까지 건드리기

그림으로 보기: 주소와 값

변수는 메모리의 어느 칸에 놓이고, 포인터는 그 칸의 번호를 담는 또 하나의 변수입니다.

0x2000000010x0x200000040x20000000p (x의 주소)0x20000008?다음 변수
x는 값 10을, p는 x의 주소를 담고 있습니다. *p = 20 을 실행하면 0x20000000 칸의 값이 바뀝니다.

p를 읽으면 주소가 나오고, *p를 읽으면 그 주소에 있는 값이 나옵니다. 별표 하나가 "그 주소로 가서"라는 뜻입니다.

포인터 연산은 자료형 크기만큼 움직인다

p + 1은 주소에 1을 더하는 것이 아니라 자료형 하나만큼 건너뜁니다.

uint8_t  *b = (uint8_t  *)0x20000000;
uint32_t *w = (uint32_t *)0x20000000;
b + 1;   // 0x20000001
w + 1;   // 0x20000004  (4바이트 건너뜀)

통신 버퍼를 uint8_t *로 받는 이유가 여기에 있습니다. 바이트 단위로 한 칸씩 움직여야 패킷을 순서대로 읽을 수 있습니다.

3D 실험실여기까지 읽은 내용을 직접 돌려 볼 수 있습니다→

레지스터에 쓰는 한 줄을 풀어 보기

#define GPIOA_ODR  (*(volatile uint32_t *)0x48000014)
GPIOA_ODR |= (1u << 5);
  1. 0x48000014라는 숫자를 "32비트 값이 있는 주소"로 바꿉니다. (volatile uint32_t *)
  2. 그 주소로 가서 값을 다룹니다. 맨 앞의 *
  3. 5번 비트만 1로 만듭니다. |= (1u << 5)

volatile이 빠지면 컴파일러가 "방금 쓴 값이니 다시 읽을 필요 없다"고 판단해 읽기나 쓰기를 지워 버릴 수 있습니다.

현업에서 자주 터지는 문제

증상 원인 확인 방법
하드폴트로 멈춤 NULL이나 초기화하지 않은 포인터를 따라감 폴트 주소 레지스터에 0 근처 값이 찍힘
값이 가끔 깨짐 함수가 끝난 지역 변수의 주소를 돌려줌 스택이 덮어써지는 시점에만 발생
옆 변수가 바뀜 배열 끝을 넘어 포인터로 씀 맵 파일에서 이웃 변수 확인
정렬 폴트 홀수 주소를 uint32_t *로 읽음 Cortex-M0에서 특히 잘 발생

포인터를 선언할 때 NULL로 초기화하고, 쓰기 전에 if (p != NULL)로 확인하는 습관만으로 첫 번째 문제는 대부분 사라집니다.

스스로 확인

  • uint16_t arr[4]에서 &arr[2] - &arr[0]의 값은 무엇이고, 주소 차이는 몇 바이트일까요?
  • 함수 인자로 구조체 전체 대신 const 포인터를 넘기면 무엇이 절약될까요?
3D 실험실에서 직접 돌려 보기값을 바꾸며 이 노트의 원리를 확인합니다→영상으로 이어 보기공부법과 진로 시리즈 15편2025 임베디드 프로그래밍 공부 순서 | 공부 방법 | 로드맵PROJECT COURSEC 문법을 실제 펌웨어 코드로 써 보고 싶다면밸런싱 로봇 하나를 요구사항, 회로와 PCB, 펌웨어, 앱까지 실무 순서대로 만드는 강의입니다. 10파트 165강.강의 살펴보기 →FREE PDF무료 전자책 3권 받기이 주제를 한 권으로 이어서 읽고 싶다면. BLDC 모터 제어, 직렬통신, 센서를 책 분량으로 묶었습니다. 이메일만 남기면 바로 받습니다.무료로 받기 →