c - 在 C 中使用 fread() 分配内存和读取数组的最便携方法

标签 c malloc fread calloc

只是想知道分配内存和 fread() 的最合理方法是什么?来自 C 文件中的数组数据。

首先解释一下:

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() 。的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* )。

因此,人们可以尝试写:

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

存在同样的问题。

那么,现在的问题是:

  1. 代码行“第 2b 行”和“第 3b 行”是否正确(忽略此问题的未定义行为)或者有一些我错过的技巧。他们的“更明智”的对应物,例如“line 2a/3a”和“line 2/3”?

  2. 编写“ list 1”代码的最安全的方法是什么,同时避免任何形式的未定义行为?

编辑(为了澄清某些方面):

讨论方向错误。编译时与运行时的问题是一回事(我也希望对此有一个标准保证,但这不是主题)。 sizeof(NULL 取消引用) 的未定义行为的问题是另一个问题。即使在编译时,我也不相信标准保证这不会导致 UB。该标准是否提供任何保证?

最佳答案

您似乎对 sizeof 运算符有错误的想法。该运算符在编译时求值,因此您传递给它的表达式在程序运行时没有机会求值。

sizeof 运算符的上下文中,*charBuffercharBuffer[0] 都是安全的,无论它们之前使用还是使用当相应的内存可用后。这只是避免键入类型名称的一种方法,因此可以减少重复。

编辑

如下所述,在编译时评估 sizeof 的规则有一个值得注意的异常(exception)(尽管它与问题中发布的代码无关)。由于 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

关于c - 在 C 中使用 fread() 分配内存和读取数组的最便携方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15131338/

相关文章:

c - 初始化指针时的数据类型警告

C - 在没有 realloc 的情况下为 stdin 动态分配数组

c - malloc block 的大小似乎有误

c - 在 C 中 fwrite/fread 动态链表的最佳方式

Csh脚本调用C程序,参数问题

c - 如何将运行时错误重定向到 STDERR?

c - 字符串比 C 语言中预期的要长

c - 这会泄漏内存吗?

c - Valgrind 显示 "invalid write of size 4 at fread"和内存泄漏

c - 我的 fread 程序有什么问题?