“sizeof(arr )”会导致未定义的行为吗?

有一个众所周知的模式来计算数组长度:

int arr[10]; size_t len = sizeof(arr) / sizeof(arr[0]); assert(len == 10); 

此模式适用于静态数组和常量大小的自动数组。 它也适用于C99中的可变长度数组。

我想应用类似的想法来计算动态数组大小(以字节为单位):

 size_t known_len = 10; int *ptr = malloc(known_len * sizeof(int)); size_t size = known_len * sizeof(ptr[0]); assert(size == known_len * sizeof(int)); 

这比known_len * sizeof(int)更好,因为sizeof(ptr[0])不引用实际的数组元素类型。 因此,它不需要代码的读者知道类型。

但是我不清楚表达式sizeof(ptr[0])会导致不确定的行为。 随着它扩大:

 sizeof(ptr[0]) -> sizeof(*((ptr) + (0))) -> sizeof(*ptr) 

如果ptr0 ,结果表达式是有问题的:

 sizeof(*((int*) 0)) 

根据C99标准:

(C99,6.3.2.3p3):“值为0的整型常量表达式,或者类型为void *的表达式,称为空指针常量。” 取消引用空指针是未定义的行为。

(C99,6.5.3.2.p4)“如果为指针指定了无效值,则一元*运算符的行为未定义.87)”

87):“unary *运算符解除引用指针的无效值是空指针,地址与指向的对象类型不一致,以及对象在其生命周期结束后的地址。”

但是从未指明这种表达式的sizeof是否会导致未定义的行为。 实际上,应该在编译时评估这样的sizeof。

我的问题是:

  • ptr类型已知并且ptr的值未知时,可以在代码中使用表达式sizeof(ptr[0])吗?
  • 根据C99标准可以certificate这种用途是合理的吗? GNU GCC规范?

表达式ptr[0]将不会在sizeof(ptr[0])求值。 大小将通过在编译时使用ptr[0]的类型来确定。

C11:6.5.3.4:

sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称。 大小由操作数的类型确定 。 结果是整数。 如果操作数的类型是可变长度数组类型,则计算操作数; 否则,不评估操作数 ,结果是整数常量。

这意味着,没有未定义的行为。

这不会导致未定义的行为。

除了获取可变长度数组的大小之外, sizeof是一个编译时常量表达式。 编译器处理表达式以确定其类型,而不生成在编译时计算表达式的代码。 因此, ptr[0] (它是一个未初始化的指针)的值根本不重要。

而且,如果你想分配十个整数,你应该像这样调用malloc

 int *ptr = malloc(known_len * sizeof(ptr[0])); 

否则,您将分配十个字节,这对于存储十个整数来说太小了。 请注意,在上面的表达式中, ptr在调用时未初始化,这对于sizeof来说非常好。

一般情况下,如果我遗漏了某些内容,则在sizeof下取消引用空指针导致未定义的行为。 从C99开始, sizeof不是纯粹的编译时构造。 如果操作数类型是VLA,则在运行时计算sizeof的操作数。

请考虑以下示例

 unsigned n = 10; int (*a)[n] = NULL; // `a` is a pointer to a VLA unsigned i = 0; sizeof a[i++]; // applying `sizeof` to a VLA 

根据C99标准,应该评估sizeof的参数(即i应该增加)。 然而,我并不完全确定a[0]中的零点解除引用应该在这里产生未定义的行为。

作为表达式(不是声明), ptr[0]*ptr相同。

只要ptr的类型已知并且它没有指向void, sizeof就可以保证在sizeof(*ptr)sizeof(ptr[0])

代码是邪恶的。

 size_t known_len = 10; int *ptr = malloc(known_len); size_t size = known_len * sizeof(ptr[0]); assert(size == known_len * sizeof(int)); 

从您的角度来看,内存分配的大小为10个字节。 这不是指向int的10个指针。

  known_len / sizeof(ptr[0]) 

将为您提供分配可以容纳的整数数。

因此,您很可能会在分配结束时导致未定义的行为。

考虑malloc(known_length * sizeof ptr [0]);