Can";sizeof(arr[0])”等;导致未定义的行为?

Can";sizeof(arr[0])”等;导致未定义的行为?,c,arrays,sizeof,c99,undefined-behavior,C,Arrays,Sizeof,C99,Undefined Behavior,计算数组长度有一个众所周知的模式: 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_

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

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\u len*sizeof(int)
更好,因为
sizeof(ptr[0])
并不是指实际的数组元素类型。因此,它不需要代码的读取器知道类型

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

sizeof(ptr[0]) -> sizeof(*((ptr) + (0))) -> sizeof(*ptr) 
如果
ptr
0
,则结果表达式有问题:

sizeof(*((int*) 0)) 
根据C99标准:

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

(C99,6.5.3.2.p4)“如果为 指针,一元
*
运算符的行为未定义。87)

87):“用于通过取消引用指针的无效值中” 一元
*
运算符是空指针,是不适当的地址 针对指向的对象类型和 对象在其生命周期结束后返回。“

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

我的问题是:

  • ptr
    的类型已知且
    ptr
    的值未知时,是否可以在代码中使用表达式
    sizeof(ptr[0])
  • 根据C99标准,这种使用是否合理?GNU GCC规范
表达式
ptr[0]
将不会在
sizeof(ptr[0])
中计算。大小将通过在编译时使用
ptr[0]
的类型来确定

C11:6.5.3.4:
sizeof
运算符生成其操作数的大小(以字节为单位),可以是表达式或类型的括号名称大小由操作数的类型决定。结果是一个整数如果操作数的类型是可变长度数组类型,则对操作数求值;否则,不计算操作数,结果为整数常量


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

这不会导致未定义的行为

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

此外,如果您想分配10个整数,您应该像这样调用
malloc

int *ptr = malloc(known_len * sizeof(ptr[0])); 
否则,将分配10个字节,这对于存储10个整数来说太小了。请注意,在上面的表达式中,
ptr
在调用时未初始化,这对于
sizeof

作为一个表达式(而不是一个声明)来说非常好,
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(已知长度*sizeof ptr[0])

在一般情况下,如果我遗漏了什么,在
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]
中的空点解引用是否会在此处产生未定义的行为。

请参阅,我已经为链接的问题添加了额外的答案。这里我关心的是当arr指针被声明为时的情况,例如,
intn=10;int(*arr)[n]=NULL,即它是指向VLA的指针。在C语言中,
sizeof
的参数如果具有VLA类型(!),则在运行时进行计算。本例中的问题是
sizeof arr[0]
是否应该产生未定义的行为。最有可能是这样的。事实上,相关问题似乎仅限于非VLA上下文,而该问题并不立即具有此类限制。这就使它成为非复制品。除此之外,请考虑<代码> Malc(NonnLeN*sieOfs*PTR)< /C> >而不是<代码> Maloc(NonnLn*sisiof(int))< /代码>。如果
ptr
的类型发生变化,或者变得模糊(深入到一些
.h
文件中),这种样式通常是正确的,并且更易于维护。你是对的,意图是malloc(已知的大小(int))。我会解决这个问题。建议删除这个答案,因为问题已经更改了。在什么情况下,
sizeof
必须在运行时实际执行它的参数?即使sizeof的参数涉及VLA,是否有任何理由
sizeof
只需返回一个隐藏变量,该变量的值将是一个有效的数字,除非程序已经参与UB?@dasblinkenlight:My poin