想知道从C文件中分配内存和fread()
数组数据的最简单方法是什么。
首先,解释:
int32_t longBuffer;
现在,当在longBuffer中进行游说时,代码可以是:
fread(&longBuffer, sizeof(longBuffer), 1, fd); //version 1
fread(&longBuffer, sizeof(int32_t), 1, fd); //version 2
在这两者中,我会说版本1更安全,因为如果longBuffer
的类型改变(让我们说int16_t
),则不必担心忘记使用新类型更新fread()
的{{1}}。
现在,对于数组数组,代码可以写成:
sizeof()
但是,这显示了第一个示例中暴露的问题:在更改//listing 1
int8_t *charpBuffer=NULL; //line 1
charpBuffer = calloc(len, sizeof(int8_t)); //line 2
fread(charpBuffer, sizeof(int8_t), len, fd); //line 3
的类型时,我们必须担心不会忘记同步sizeof(<type>)
指令(比方说,charpBuffer
到int8_t*
)。
所以,有人可能会写:
int16_t*
作为更安全的错误版本。这应该有效,因为在第2行分配之后,写fread(charpBuffer, sizeof(charpBuffer[0]), len, fd); //line 3a
完全有效。
另外,有人可以写:
charpBuffer[0]
但是,尝试对内存分配执行相同操作,例如:
fread(charpBuffer, sizeof(*charpBuffer), len, fd); //line 3b
虽然语法更好,但表现出未定义的行为,因为在此阶段,将charpBuffer = calloc(len, sizeof(charpBuffer[0])); //line 2a
结果写入取消引用NULL指针。另外,写作:
charpBuffer[0]
表现出同样的问题。
所以,现在问题:
代码行“2b”和“3b”是否正确(忽略此问题的未定义行为)或者有一些我想念的技巧w.r.t.他们的“明智”对应物如“2a / 3a”和“2/3行”?
编写“清单1”代码最容易出错的方法是什么,但避免任何形式的未定义行为?
EDITS(为了澄清某些方面):
讨论采取了错误的方向。编译时间与运行时间的问题是一回事(我也希望对这个问题有一个标准的保证,但这不是主题)。而对于sizeof(NULL解除引用)的未定义行为的问题是另一个问题。即使在编译时,我也不相信标准可以保证不会导致UB。标准是否提供任何保证?
答案 0 :(得分:3)
您似乎对sizeof
运算符有错误的想法。此编译器在编译时进行求值,因此传递给它的表达式在程序运行时无法被评估。
在sizeof
运算符的上下文中,*charBuffer
和charBuffer[0]
都是安全的,无论它们是在相应内存可用之前还是之后使用。这只是一种避免输入类型名称的方法,因此可以减少重复。
修改强>
如下所述,在编译时评估sizeof
的规则有一个值得注意的例外(尽管它与问题中发布的代码无关)。由于C和C ++允许可变长度数组作为自动变量,因此对它们应用sizeof
实际上可能涉及一些运行时开销。
关于你对未定义行为的担忧,我认为从那以后就没有理由:
int vla[n]; // declare a variable-length array of length n
/* The compiler will produce code using the value of n prior to
declaring the array to compute its size. */
x = sizeof(vla);
/* The space for the array is already available, so the expression
*vla is not UB anywhere (except if n is 0). Furthermore, n is
not involved in the computation and the operator can be evaluated at
compile-time. */
y = sizeof(*vla);
z = sizeof(vla[0]); // same thing
答案 1 :(得分:2)
从C99 6.5.4.3.2(强调我的):
sizeof
运算符产生其操作数的大小(以字节为单位) 可以是表达式或类型的带括号的名称。大小是 根据操作数的类型确定。结果是整数。 如果操作数的类型是可变长度数组类型,则 操作数被评估;否则,操作数不被评估和 结果是一个整数常量。
操作数“未评估”意味着访问sizeof(charBuffer[0])
或sizeof(*charBuffer)
非常安全,因为这些表达式仅用于其类型。同一页面上的示例3继续显式地记录sizeof array / sizeof array[0]
用于计算数组中元素数量的习惯用语,而没有任何提及或暗示它对空数组无效。