C에서 char 배열과 char 포인터의 차이점은 무엇입니까?
C99 N1256 초안
문자열 리터럴에는 두 가지 용도가 있습니다.
초기화 char[]
:
char c[] = "abc";
이것은 "더 많은 마법"이며 6.7.8 / 14 "초기화"에 설명되어 있습니다.
문자 유형의 배열은 선택적으로 중괄호로 묶인 문자열 리터럴로 초기화 될 수 있습니다. 문자열 리터럴의 연속 문자 (공간이 있거나 배열의 크기를 알 수없는 경우 종료 널 문자 포함)는 배열의 요소를 초기화합니다.
따라서 이것은 바로 가기입니다.
char c[] = {'a', 'b', 'c', '\0'};
다른 일반 배열과 마찬가지로 c
수정할 수 있습니다.
다른 곳에서는 :
그래서 당신이 쓸 때 :
char *c = "abc";
이것은 다음과 유사합니다.
/* __unnamed is magic because modifying it gives UB. */
static char __unnamed[] = "abc";
char *c = __unnamed;
에서 암시 적 캐스트 주 char[]
에 char *
항상 합법적이다.
그런 다음 수정 c[0]
하면 __unnamed
UB 도 수정 됩니다.
이것은 6.4.5 "문자열 리터럴"에 문서화되어 있습니다 :
5 변환 단계 7에서는 문자열 리터럴 또는 리터럴에서 생성 된 각 멀티 바이트 문자 시퀀스에 값이 0 인 바이트 또는 코드가 추가됩니다. 그런 다음 멀티 바이트 문자 시퀀스는 시퀀스를 포함하기에 충분한 정적 저장 기간 및 길이의 배열을 초기화하는 데 사용됩니다. 문자열 리터럴의 경우 배열 요소에는 char 유형이 있으며 멀티 바이트 문자 시퀀스의 개별 바이트로 초기화됩니다 [...]
6 해당 배열에 적절한 값이있는 경우 이러한 배열이 고유한지 여부는 지정되지 않았습니다. 프로그램이 이러한 배열을 수정하려고하면 동작이 정의되지 않습니다.
6.7.8 / 32 "초기화"는 직접적인 예를 제공합니다.
예 8 : 선언
char s[] = "abc", t[3] = "abc";
"일반"문자 배열 객체를 정의 s
하고t
요소가 문자열 리터럴로 초기화됩니다.
이 선언은
char s[] = { 'a', 'b', 'c', '\0' },
t[] = { 'a', 'b', 'c' };
배열의 내용을 수정할 수 있습니다. 한편, 선언
char *p = "abc";
p
"pointer to char"유형으로 정의 하고 길이가 4 인 "array of char"유형의 객체를 가리 키도록 초기화합니다. p
배열의 내용을 수정하는 데 사용하려고 하면 동작이 정의되지 않습니다.
GCC 4.8 x86-64 ELF 구현
프로그램:
#include <stdio.h>
int main(void) {
char *s = "abc";
printf("%s\n", s);
return 0;
}
컴파일 및 디 컴파일 :
gcc -ggdb -std=c99 -c main.c
objdump -Sr main.o
출력 내용 :
char *s = "abc";
8: 48 c7 45 f8 00 00 00 movq $0x0,-0x8(%rbp)
f: 00
c: R_X86_64_32S .rodata
결론 : GCC는 char*
이를 .rodata
섹션이 아닌 섹션에 저장 합니다 .text
.
우리가 같은 일을한다면 char[]
:
char s[] = "abc";
우리는 얻는다 :
17: c7 45 f0 61 62 63 00 movl $0x636261,-0x10(%rbp)
스택에 저장됩니다. %rbp
).
그러나 참고 기본 링커 스크립트 박았 .rodata
및 .text
실행이 동일한 세그먼트,하지만 쓰기 권한이있다. 이것은 다음과 같이 볼 수 있습니다.
readelf -l a.out
포함하는:
Section to Segment mapping:
Segment Sections...
02 .text .rodata
char p[3] = "hello";
초기화 문자열이 선언 한 배열의 크기에 비해 너무 깁니다. 오식?