코드가 잘못됐다 하시는분 있는데
절대 아닙니다.
[root@archlinux ~]# cat test.c
#include <stdio.h>
int main(int argc, char **argv) {
char *p = &"ABCD";
printf("%x \n", p);
printf("%x \n", p+1);
printf("%x \n", p+2);
printf("%x \n", p+3);
printf("%x \n", p+4);
printf("------------\n");
printf("%x %x \n", &"ABCD", p);
return 0;
}
흔해빠진 포인터 예제군요.
&"ABCD"가 틀렸다고 하신분. 틀렸다고 하신게 틀렸습니다.
"ABCD"는 컴파일 타임에 rodata 로 넘어가고 임시 심볼로 대체 됩니다. 그러므로 정당한 문법입니다.
[root@archlinux ~]# gcc test.c -S
test.c: In function ‘main’:
test.c:4:12: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
char *p = &"ABCD";
[root@archlinux ~]# cat test.s
.file "test.c"
.section .rodata
.LC0:
.string "ABCD"
.LC1:
.string "%x \n"
.LC2:
.string "------------"
.LC3:
.string "%x %x \n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
subq $32, %rsp
movl %edi, -20(%rbp)
movq %rsi, -32(%rbp)
movq $.LC0, -8(%rbp)
movq -8(%rbp), %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
addq $1, %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
addq $2, %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
addq $3, %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movq -8(%rbp), %rax
addq $4, %rax
movq %rax, %rsi
movl $.LC1, %edi
movl $0, %eax
call printf
movl $.LC2, %edi
call puts
movq -8(%rbp), %rax
movq %rax, %rdx
movl $.LC0, %esi
movl $.LC3, %edi
movl $0, %eax
call printf
movl $0, %eax
leave
.cfi_def_cfa 7, 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (GNU) 5.3.0"
.section .note.GNU-stack,"",@progbits
대충 패턴 보이죠? C 코드에서 포인터 참조 한 것과, +1 +2 +3 한 부분입니다.
[root@archlinux ~]# gcc test.c -c
test.c: In function ‘main’:
test.c:4:12: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
char *p = &"ABCD";
^
[root@archlinux ~]# objdump test.o -D
test.o: file format elf64-x86-64
생략
Disassembly of section .rodata:
0000000000000000 <.rodata>:
0: 41 rex.B
1: 42 rex.X
2: 43 rex.XB
3: 44 00 25 78 20 0a 00 add %r12b,0xa2078(%rip) # a2082 <main+0xa2082>
a: 2d 2d 2d 2d 2d sub $0x2d2d2d2d,%eax
f: 2d 2d 2d 2d 2d sub $0x2d2d2d2d,%eax
14: 2d 2d 00 25 78 sub $0x7825002d,%eax
19: 20 25 78 20 0a 00 and %ah,0xa2078(%rip) # a2097 <main+0xa2097>
링크 하기 전이라, 00으로 시작하는군요.
그렇다면 링크까지 한다면?
[root@archlinux ~]# gcc test.c
test.c: In function ‘main’:
test.c:4:12: warning: initialization from incompatible pointer type [-Wincompatible-pointer-types]
char *p = &"ABCD";
^
[root@archlinux ~]# objdump a.out -D
a.out: file format elf64-x86-64
생략
Disassembly of section .rodata:
0000000000400680 <_IO_stdin_used>:
400680: 01 00 add %eax,(%rax)
400682: 02 00 add (%rax),%al
400684: 41 rex.B
400685: 42 rex.X
400686: 43 rex.XB
400687: 44 00 25 78 20 0a 00 add %r12b,0xa2078(%rip) # 4a2706 <__FRAME_END__+0xa1f3e>
40068e: 2d 2d 2d 2d 2d sub $0x2d2d2d2d,%eax
400693: 2d 2d 2d 2d 2d sub $0x2d2d2d2d,%eax
400698: 2d 2d 00 25 78 sub $0x7825002d,%eax
40069d: 20 25 78 20 0a 00 and %ah,0xa2078(%rip) # 4a271b <__FRAME_END__+0xa1f53>
400684 에서 시작 하는군요.
실행 결과 볼까요?
[root@archlinux ~]# ./a.out
400684
400685
400686
400687
400688
------------
400684 400684
네. 예제 자체는 문제도 없었고 의도는 다음과 같습니다.
1. 문자열 상수는 어디에 저장될까? 찍어보자.
2.
printf("%x %x \n", &"ABCD", p);
두가지 "ABCD"는 같은가? 찍어보자.
이런 정상적인 예제를 왜 printf 로 A 찍고 B 찍고 C 찍는다고 마음대로 수정해서 설명하고 있는지 모르겠네요.
이런 예제는 빌드해서 돌리는데 몇십분씩 안걸립니다.
틀렸다고 주장하기 전에 한번이라도 빌드 돌리고 이야기 하시면 좋겠군요.