NULL 是有效的 FILE* 吗?

Is NULL a valid FILE*?

我想要一个类似于

的函数
/*In header*/
void foo(FILE *outpt=stdout);

/*In implementation*/
void foo(FILE *outpt)
{
    if(outpt) fprintf(outpt, "Hello!");
}

但如果 NULL==stdout,此代码(显然)已损坏。 (编辑: Jonathan Leffler 指出此代码已经损坏,因为 C 没有默认参数。我的 C++ 正在显示,但想法仍然存在。)

C 指定 stdinstdoutstderr 是实现定义的 FILE* 常量,但我找不到表明这些常量是不是 NULL。此外,我找不到任何暗示 NULL 可能不是有效打开文件的信息!

在 MSVS 中,fprintf(NULL, "Hello!") 调用 abort(),表明 NULL 确实是一个无效的 FILE* 规范。

C++在这方面似乎效仿了C。我最终是一名 C++ 程序员,但我会选择 C ​​答案,因为它可能会转移到 C++ 以实现向后兼容性。所以:C 或 C++ 规范(包括 C2x 和 C++20)是否保证 NULL 是无效的 FILE* 规范?

根据定义,NULL 指针不指向 任何 类型的有效对象。指针类型是否为 FILE * 无关紧要。

C standard 的第 6.3.2.3p3 节说明了以下关于 NULL 指针的内容:

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

尝试取消引用 NULL 指针会调用 undefined behavior

关于间接运算符的 C 标准第 6.5.3.3p4 节指出:

The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object.
If the operand has type ‘‘pointer totype’’, the result has type ‘‘type’’. If an invalid value has been assigned to the pointer, the behavior of the unary *operator is undefined. 102)

脚注 102 指出:

... Among the invalid values for dereferencing a pointer by the unary * operator are a null pointer, an address inappropriately aligned for the type of object pointed to, and the address of an object after the end of its lifetime.

由于这些通常适用于 NULL 指针,因此扩展意味着 FILE * 被设置为 NULL 并不指向有效的 FILE 对象。

NULL 不是有效的文件*!由于 stdout 和 stdin 被视为任何其他流,因此适用以下内容......

https://man7.org/linux/man-pages/man3/fopen.3.html

RETURN VALUE Upon successful completion fopen(), fdopen() and freopen() return a FILE pointer. Otherwise, NULL is returned and errno is set to indicate the error.

C11 7.21.1/3这样描述标准文件句柄:

The macros are […]

stderr
stdin
stdout

which are expressions of type "pointer to FILE" that point to the FILE objects associated, respectively, with the standard error, input, and output streams.

如果它们的值为空,它们将不会指向任何此类对象。