gpt4 book ai didi

c - 这种对函数声明的滥用是否会引发未定义的行为?

转载 作者:太空狗 更新时间:2023-10-29 17:24:22 32 4
gpt4 key购买 nike

考虑以下程序:

int main()
{
int exit();
((void(*)())exit)(0);
}

如您所见,exit 声明为错误的返回类型,但从未使用错误的函数类型调用。这个程序的行为是否定义明确?

最佳答案

MSVC 对该程序没有问题,但 gcc 有(至少 gcc 4.6.1)。它发出以下警告:

test.c: In function 'main':
test.c:3:9: warning: conflicting types for built-in function 'exit' [enabled by default]
test.c:4:22: warning: function called through a non-compatible type [enabled by default]
test.c:4:22: note: if this code is reached, the program will abort

而且,正如 promise 的那样,它在运行时确实会崩溃。崩溃不是由于调用约定不正确或其他原因引起的——gcc 实际上生成了一个未定义的指令,其操作码为 0x0b0f 以显式强制崩溃(gdb 将其反汇编为 ud2——我还没有查找那是什么CPU 手册可能会说明操作码):

main:
.LFB0:
.cfi_startproc
push ebp
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
mov ebp, esp
.cfi_def_cfa_register 5
.value 0x0b0f
.cfi_endproc

我不愿意说 gcc 这样做是错误的,因为我确信编写该编译器的人比我更了解 C。但这是我阅读标准的方式;我确定有人会指出我遗漏的内容:

C99 关于函数指针的转换(6.3.2.3/8“指针”)是这样说的:

A pointer to a function of one type may be converted to a pointer to a function of another type and back again; the result shall compare equal to the original pointer. If a converted pointer is used to call a function whose type is not compatible with the pointed-to type, the behavior is undefined.

在表达式中,标识符 exit 的计算结果为函数指针。

子表达式 ((void(*)())exit)exit 求值的函数指针转换为 类型的函数指针无效 (*)()。然后通过该指针进行函数调用,传递 int 参数 0。

标准库包含一个名为 exit 的函数,其原型(prototype)如下:

void exit(int status);

标准还说(7.1.4/2“库函数的使用”):

Provided that a library function can be declared without reference to any type defined in a header, it is also permissible to declare the function and use it without including its associated header.

您的程序不包含包含该原型(prototype)的 header ,但通过转换后的指针进行的函数调用使用了转换中提供的“声明”。 cast中的声明不是原型(prototype)声明,所以需要判断标准库定义的exit的函数类型和你程序中转换后的函数指针的函数类型是否兼容.标准说(6.7.5.3/15“函数声明符(包括原型(prototype))”)

For two function types to be compatible, both shall specify compatible return types. ... If one type has a parameter type list and the other type is specified by a function declarator that is not part of a function definition and that contains an empty identifier list, the parameter list shall not have an ellipsis terminator and the type of each parameter shall be compatible with the type that results from the application of the default argument promotions

在我看来,转换后的函数指针具有兼容的函数类型——返回类型是相同的(void)并且单个参数的类型是int在默认参数提升之后。所以在我看来,这里没有未定义的行为。


更新:对此稍作思考后,将 7.1.4/2 解释为“自声明”库函数名称必须正确声明(虽然不一定使用原型(prototype),但使用正确的返回类型)。特别是因为该标准还表示“在以下任何子条款中具有外部链接的所有标识符......始终保留用作具有外部链接的标识符”(7.1.3)。

所以我认为可以合理地论证该程序具有未定义的行为。

关于c - 这种对函数声明的滥用是否会引发未定义的行为?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16493058/

32 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com