1. 문제 개요
C와 C++에서 문자열 리터럴은 코드에서 자주 사용되지만, 이를 수정하려고 하면 예기치 않은 오류가 발생할 수 있습니다. 문자열 리터럴이 저장되는 위치와 수정 불가능한 이유를 이해하면 프로그램 안정성을 높이고 디버깅 과정을 단축할 수 있습니다.
간단한게 문자열 리터럴이 어디에 저장되는지 알아보고, 메모리에 대해서 자세히 깊이있게 궁금하다면 글을 끝까지 읽어보세요!
2. 문자열 리터럴의 저장 위치
2.1 문자열 리터럴의 저장 원리
문자열 리터럴은 일반적으로 읽기 전용 데이터(Read-Only Data) 섹션에 저장됩니다. 이 영역은 실행 파일의 .rodata
섹션에 위치하며, 운영 체제에 의해 읽기 전용으로 설정됩니다.
예제:
char *s = "hello";
"hello"
문자열은.rodata
섹션에 저장됩니다.- 포인터
s
는 이 문자열의 시작 주소를 가리킵니다. - 수정 시도: 읽기 전용 메모리를 수정하려 하면 세그멘테이션 오류(segmentation fault)가 발생합니다.
2.2 플랫폼별 차이
- 일반적인 시스템: 대부분의 현대 운영 체제(Windows, Linux, macOS)는
.rodata
섹션을 읽기 전용으로 설정하여 안전성을 보장합니다. - 임베디드 시스템: 일부 단순한 아키텍처에서는 읽기 전용 메모리 구역을 지원하지 않을 수 있습니다. 이 경우, 문자열 리터럴이 쓰기 가능한 데이터 영역에 저장될 수 있습니다.
3. 문자열 리터럴과 배열의 차이점
3.1 문자열 리터럴을 사용하는 경우
char *s = "hello";
- 문자열
"hello"
는 읽기 전용 메모리에 저장됩니다. - 포인터
s
는 수정할 수 있지만, 가리키는 문자열 자체는 수정할 수 없습니다:
s = "world"; // 가능: 포인터가 다른 문자열을 가리킴
s[0] = 'H'; // 오류: 읽기 전용 메모리 수정 시도
3.2 배열을 사용하는 경우
char s[] = "hello";
- 문자열
"hello"
는 읽기 전용 메모리에서 복사되어 스택 메모리에 저장됩니다. - 배열
s
는 수정 가능합니다:
s[0] = 'H'; // 가능: 스택 메모리에 저장된 데이터 수정
4. 메모리 구조 탐구
4.1 .rodata
섹션에 저장된 문자열
문자열 리터럴은 컴파일 시 .rodata
섹션에 저장되며, 실행 중에는 읽기 전용 메모리로 매핑됩니다.
#include <stdio.h>
int main() {
char *s = "hello";
printf("%s\n", s);
return 0;
}
컴파일 명령:
gcc -o example example.c
objdump -s -j .rodata example
출력:
.rodata
섹션에 문자열"hello"
가 저장되어 있는 것을 확인할 수 있습니다.
4.2 배열을 사용하는 경우
배열은 런타임에 스택 메모리에 저장됩니다:
char s[] = "hello";
- 초기값은
.rodata
섹션에서 가져오지만, 데이터는 수정 가능한 스택 메모리에 저장됩니다.
5. 문자열 리터럴 사용 시 주의사항
5.1 수정 불가능한 문자열 리터럴
문자열 리터럴을 수정하려고 하면 정의되지 않은 동작(Undefined Behavior)이 발생합니다. 컴파일러나 실행 환경에 따라 결과가 달라질 수 있습니다.
5.2 안전한 문자열 수정 방법
문자열을 수정해야 하는 경우 배열을 사용합니다:
char s[] = "modifiable";
s[0] = 'M'; // 안전
6. 결론
- 문자열 리터럴은 일반적으로 읽기 전용 메모리에 저장되며, 수정할 수 없습니다.
- 수정 가능한 문자열이 필요하면 배열을 사용해야 합니다.
- 문자열 리터럴의 저장 위치와 동작 원리를 이해하면 안정적인 코드 작성과 디버깅에 큰 도움이 됩니다.