只是想知道fread()
从 C 中的文件分配内存和数组数据的最合理方法是什么。
首先,一个解释:
int32_t longBuffer;
现在,当在 longBuffer 中进行 freading 时,代码可以如下所示:
fread(&longBuffer, sizeof(longBuffer), 1, fd); //version 1
fread(&longBuffer, sizeof(int32_t), 1, fd); //version 2
在这两者中,我会说版本 1 更安全,因为如果类型发生longBuffer
变化(比如说 to int16_t
),人们不必担心忘记用新类型更新fread()
's 。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*
to int16_t*
)。
所以,有人可能会尝试写:
fread(charpBuffer, sizeof(charpBuffer[0]), len, fd); //line 3a
作为一个更安全的版本。这应该有效,因为在第 2 行分配之后,写入charpBuffer[0]
是完全有效的。
此外,还可以写:
fread(charpBuffer, sizeof(*charpBuffer), len, fd); //line 3b
但是,尝试对内存分配做同样的事情,例如:
charpBuffer = calloc(len, sizeof(charpBuffer[0])); //line 2a
虽然语法更好,但表现出未定义的行为,因为在这个阶段,将charpBuffer[0]
结果写入取消引用 NULL 指针。另外,写作:
charpBuffer = calloc(len, sizeof(*charpBuffer)); //line 2b
表现出同样的问题。
所以,现在的问题:
代码行“line 2b”和“line 3b”是否正确(忽略此问题的未定义行为)或者我错过了一些技巧,例如“line 2a/3a”和“line 2” /3”?
编写“清单 1”代码但避免任何形式的未定义行为的最安全的方式是什么?
编辑(为了澄清某些方面):
讨论的方向错了。编译时间与运行时间的问题是一回事(我也想对此有一个标准的保证,但这不是主题)。sizeof(NULL dereferencing) 的未定义行为问题是另一个问题。即使在编译时,我也不相信标准保证不会导致 UB。该标准是否提供任何保证?