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