在我的环境中,以下代码可以正常运行,但是可以保证吗?
FILE *file = fopen("in", "r");
int *read_to = NULL;
size_t count = 0;
size_t read = fread(read_to, sizeof(*read_to), count, file);
fclose(file);
分别
FILE *file = fopen("out", "w");
int *write = NULL;
size_t count = 0;
size_t written = fwrite(write, sizeof(*write), count, file);
fclose(file);
答案 0 :(得分:5)
这不能保证正常工作,对标准的严格阅读会得出这样的结论:将空指针作为第一个参数传递给fread()
或fwrite()
会导致不确定的行为。
根据§7.21.8.1 ¶2 of the C11 Draft Standard:
size_t fread(无效*限制ptr, size_t大小,size_t nmemb, FILE *限制流);
读取函数将读取到 ptr 指向的数组中。...
类似地,在§7.21.8.2 ¶2中:
size_t fwrite(常量无效*限制ptr, size_t大小,size_t nmemb, FILE *限制流);
fwrite 函数从 ptr 指向的数组中写入。...
但是,在描述库函数(§7.1.4)的用法的部分中指出:
如果函数的参数具有无效值(例如,函数的域外的值,程序地址空间外的指针,空指针或指向不可修改存储的指针),则相应的参数不是const限定的)或变量数目可变的函数所不希望的类型(升级后),则行为未定义。 如果将函数参数描述为数组,则实际传递给该函数的指针应具有一个值,以使所有地址计算和对对象的访问(如果指针确实指向该函数的第一个元素,则该值将是有效的数组)实际上是有效的。
最后,在§4 ¶2中:
如果违反了在约束或运行时约束之外出现的“应”或“不应”要求,则该行为未定义。
由于空指针未指向有效对象,因此地址计算和访问对空指针无效,因此将空指针传递到fread()
或fwrite()
会违反§的“ shall” 7.1.4,因此行为是不确定的。
答案 1 :(得分:3)
“ N1570委员会草案-2011年4月12日ISO / IEC 9899:201x”在7.21.8中说
如果size或nmemb为零, fread返回零,数组的内容和流的状态保持不变 保持不变。
和
如果size或nmemb为零, fwrite返回零,流的状态保持不变。
基于以上文字,我希望它是有效的。
答案 2 :(得分:-1)
是否定义行为取决于是否将null参数视为“无效”。以上行为的描述完全描述了 fread
和fwrite
在大小为零时的行为,忽略了数据指针:{{1 }}将返回零而没有副作用-应该可以执行此操作而无需查看传入的指针。
唯一的危险是,某些编译器作者可能无法识别7.1.4中的“例如”语言来提供错误程序可能以要求函数执行“不可能”动作的方式传递的示例(例如从空地址读取或写入数据字节,或取消引用空指针或写入const限定的存储区),而是将列表视为指示此类自变量无效的规范化规范,即使在可能的情况下自然会被忽略。尽管怀疑后一种处理是否会在人为的方案之外提供任何有意义的性能优势,但认为“聪明”和“愚蠢”是反义词的编译器作者可能会使用后一种处理来证明“优化”。
质量实现将fread(any,0,0,file)视为无操作,而不考虑数据指针是否为null,因为这样做将以零成本提供一些好处。
关于使用fwrite写入各种数据(包括由指针+ size_t组合标识的可选块)以及向调用者说明(null + 0)是指示无可选数据的有效方式的代码,对于大小为零的情况,应该使用特殊的处理方式,我想这取决于代码是由高质量的编译器还是“聪明的”编译器处理。