在C语言中检查函数是否已定义是否有效?

4
void f();
int main(int argc, char** argv)
{
    if (f)
    {
        // other code
    }
}

在使用VS2017时,链接器会抱怨未解决的外部符号,而在GCC中可以正常工作。根据C99规范,这是有效的吗?还是实现细节?


但如果该函数不存在,它在gcc上就无法编译通过? 它要么编译通过并且始终为真,要么无法编译通过... - Jason
1
https://onlinegdb.com/Dwmxd9U0R - user20291889
在嵌入式代码中,通常会检查弱函数是否已定义(通常是用户定义的回调函数)。 - user20291889
2
@Jason:关于“但如果函数不存在,gcc编译器不会通过?”的问题:void f();是一个声明,无论函数是否存在,它和if (f)都可以编译通过。函数的存在与否只在链接时才有影响,而不是编译时。 - Eric Postpischil
1
我认为在这里标记语言警察并不实用。就C规范而言,void f();声明了函数 f,它在if (f)中的使用导致其转换为指向函数的指针,并且该指针不能是空指针,因此if语句总是为真。这就是你从标准中所能获得的全部信息。弱链接和测试函数是否可用超出了C标准的范围。 - Eric Postpischil
显示剩余7条评论
3个回答

3

C标准要求在正确的程序中每个符号都应该只被定义一次,但是如果违反该规则,则不需要进行任何诊断。因此,如果您声明了一个从未在任何编译单元中定义的函数,则使用该函数是超出C规范范围的。

已知gcc编译器有很多扩展,其中一些也被clang接受。如果你知道自己只会使用gcc,请使用它们;如果你想编写可移植的程序,则不应这样做。


0

GCC将已声明的函数视为始终存在, 即使使用-O0,也会对代码进行优化:

#include <stdio.h>

int main(int argc, char** argv)
{
    printf("Y\n");
}

如果您在编译器命令行中添加常见的警告选项,GCC也会对此发出警告。

这并不是那么清晰明了的。 - Konrad Rudolph
这个例子基于楼主的原始代码,但我的回答还不完整。 - the busybee
我正在使用属性注释,为了Godbolt。如果我没记错的话,你不需要更改代码来将符号注释为弱符号,你也可以通过链接器脚本在行外定义它。 - Konrad Rudolph
如果你在链接脚本中将符号注释为弱符号,编译器并不会知道这一点 - 并且会很高兴地进行优化。 :-D - the busybee
我记得有一个命令行选项可以告诉GCC接受来自其他地方的弱注释,但现在我找不到它了。 - Konrad Rudolph
@KonradRudolph 我也发现 __attribute__((weak)) 会让 GCC if (f) 优化成 if (1) - pmor

-1
通常在嵌入式代码中检查弱函数是否已定义(通常是用户定义的回调)是很常见的。
不,这从来没有被做过,因为它无法完成。您的代码可能有一些指向函数的指针,您可以检查这些指针是否不为空(即已分配某些函数指针引用),但无法检查这些引用是否正确。

2
例如:https://github.com/hathach/tinyusb/blob/55db123a85d464462562f4c64efa8d6ff5734dce/src/device/usbd.c#L1366 - user20291889
我知道许多嵌入式代码使用你所描述的方式,也许并不是很常见,但确实存在。 - user20291889

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接