a 和 a + 0 作为 C 指针有什么区别?
What's the difference between a and a + 0 as C pointers?
看C代码。
#include <stdio.h>
int main(void)
{
int v[3] = {1, 2, 3};
printf("%d\n", v);
printf("%d\n", v + 0);
printf("%zu\n", sizeof(v));
printf("%zu\n", sizeof(v + 0));
printf("%zu\n", sizeof(v + 1));
printf("%zu\n", sizeof(v + 2));
return 0;
}
这是输出之一:
-587904464
-587904464
12
8
8
8
我认为v和v+0是一样的
两者都是指向数组 v[3] 中第一个元素的指针。
因此,v 和 v+0 具有相同的值。
但为什么它们不能保存相同的字节? (sizeof(v) 和 sizeof(v + 0) 不同)
在大多数 情况下,数组标识符衰减为指向数组第一个元素的指针。但是,当数组是 sizeof
运算符的操作数时,不会发生这种转换,并且运算符会产生数组的大小(以字节为单位)。 From §6.3.2.1 ¶3 of the C11 Draft Standard:
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue.
请注意,在 C18 标准中,_Alignof
运算符已从该段落中删除 ()。
因此,sizeof(v)
得出数组 v[]
的大小(以字节为单位),即 12 字节。也就是说,操作数的 type 是 int [3]
因为数组没有被转换为指向 int
的指针(就像在大多数表达式中一样),并且 sizeof
运算符产生这种类型的大小(一个 3 int
s 的数组)以字节为单位。
但是对于 sizeof (v + 0)
,表达式 v + 0
的 type 决定了 sizeof
运算符产生的结果。在表达式v + 0
中,数组v[]
衰减为指向v[]
第一个元素的指针,然后根据指针运算规则添加0
。结果是指向 int
的指针(因为 &v[0]
本身就是指向 int
的指针),所以表达式 v + 0
的类型是 int *
。在这种情况下,sizeof
运算符因此产生指向 int
的指针的大小。类似的表达方式sizeof (v + 1)
等也是如此
顺便说一句,请注意,在第一次转换为 void *
后,您必须使用 %p
转换说明符打印地址以避免未定义的行为:
printf("%p\n", (void *)v);
printf("%p\n", (void *)(v + 0));
看C代码。
#include <stdio.h>
int main(void)
{
int v[3] = {1, 2, 3};
printf("%d\n", v);
printf("%d\n", v + 0);
printf("%zu\n", sizeof(v));
printf("%zu\n", sizeof(v + 0));
printf("%zu\n", sizeof(v + 1));
printf("%zu\n", sizeof(v + 2));
return 0;
}
这是输出之一:
-587904464
-587904464
12
8
8
8
我认为v和v+0是一样的
两者都是指向数组 v[3] 中第一个元素的指针。
因此,v 和 v+0 具有相同的值。
但为什么它们不能保存相同的字节? (sizeof(v) 和 sizeof(v + 0) 不同)
在大多数 情况下,数组标识符衰减为指向数组第一个元素的指针。但是,当数组是 sizeof
运算符的操作数时,不会发生这种转换,并且运算符会产生数组的大小(以字节为单位)。 From §6.3.2.1 ¶3 of the C11 Draft Standard:
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, or is a string literal used to initialize an array, an expression that has type ''array of type'' is converted to an expression with type ''pointer to type'' that points to the initial element of the array object and is not an lvalue.
请注意,在 C18 标准中,_Alignof
运算符已从该段落中删除 (
因此,sizeof(v)
得出数组 v[]
的大小(以字节为单位),即 12 字节。也就是说,操作数的 type 是 int [3]
因为数组没有被转换为指向 int
的指针(就像在大多数表达式中一样),并且 sizeof
运算符产生这种类型的大小(一个 3 int
s 的数组)以字节为单位。
但是对于 sizeof (v + 0)
,表达式 v + 0
的 type 决定了 sizeof
运算符产生的结果。在表达式v + 0
中,数组v[]
衰减为指向v[]
第一个元素的指针,然后根据指针运算规则添加0
。结果是指向 int
的指针(因为 &v[0]
本身就是指向 int
的指针),所以表达式 v + 0
的类型是 int *
。在这种情况下,sizeof
运算符因此产生指向 int
的指针的大小。类似的表达方式sizeof (v + 1)
等也是如此
顺便说一句,请注意,在第一次转换为 void *
后,您必须使用 %p
转换说明符打印地址以避免未定义的行为:
printf("%p\n", (void *)v);
printf("%p\n", (void *)(v + 0));