遇到了一个坑,记录一下。
#include <stdio.h>
char str[10];
int main()
{
printf("str = %p\n", str);
printf("&str = %p\n", &str);
printf("str+1 = %p\n", str+1);
printf("&str+1 = %p\n", &str+1);
return 0;
}
运行结果:
str = 0x556749e01018
&str = 0x556749e01018
str+1 = 0x556749e01019
&str+1 = 0x556749e01022
数组名的值是一个指针常量,也就是数组第一个元素的地址
,它的数据类型取决于数组元素的类型,如果是int
数组,那么数组名的类型就是指向int
的常量指针。str
等价于&str[0]
,str
是char
型数组,则str
就是指向char
型的指针常量,所以str+1
就是str + sizeof(char)
。
但是有一个例外,当数组名作为sizeof
或者&
的操作数时,数组名不是一个指针常量。sizeof(str)
等于10
,是数组的长度,而不是指向数组的指针的长度。&str
是指向数组的指针,而不是指向指针常量的指针。虽然str
和&str
的值相同,但是二者是不同的指针类型,str
指向str[0]
的指针,而&str
是指向数组的指针,因此&str+1
等价于str + sizeof(str)
。
gcc -S test.c
的汇编结果如下:
.file "test.c"
.text
.comm str,10,8
.section .rodata
.LC0:
.string "str = %p\n"
.LC1:
.string "&str = %p\n"
.LC2:
.string "str+1 = %p\n"
.LC3:
.string "&str+1 = %p\n"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
endbr64
pushq %rbp
.cfi_def_cfa_offset 16
.cfi_offset 6, -16
movq %rsp, %rbp
.cfi_def_cfa_register 6
leaq str(%rip), %rsi // 对应str
leaq .LC0(%rip), %rdi
movl $0, %eax
call printf@PLT
leaq str(%rip), %rsi // 对应&str,可见汇编是一样的
leaq .LC1(%rip), %rdi
movl $0, %eax
call printf@PLT
leaq 1+str(%rip), %rax // 对应str+1
movq %rax, %rsi
leaq .LC2(%rip), %rdi
movl $0, %eax
call printf@PLT
leaq 10+str(%rip), %rax // 对应&str+1
movq %rax, %rsi
leaq .LC3(%rip), %rdi
movl $0, %eax
call printf@PLT
movl $0, %eax
popq %rbp
.cfi_def_cfa 7, 8
ret
.cfi_endproc