检查C中是否存在外部定义的标识符

时间:2010-10-12 02:32:01

标签: c darwin weak-linking

我在使用Objective-C for iOS进行开发时遇到了这个问题,但这应该适用于使用Mac OS X / iOS链接器的任何C / C ++ / Objective-C代码。该解决方案由another question涵盖,但我对为什么感兴趣。

假设我正在使用链接到定义常量的库。在头文件中有一个这样的声明:

extern char * const BrandNewIdentifier;

我想编译我的应用程序并在具有早期版本库的系统上运行它,其中该常量没有定义,所以为了安全起见我不认为它已被定义。

现在,如果有一个只在最新版本的库中定义的函数,我可以这样做:

if (BrandNewFunc) {
    BrandNewFunc("foobar", 42);
} else {
    printf("Your system does not support some thing.");
}

BrandNewFunc的计算结果为NULL,而不是包含函数代码的地址。我认为常量的行为方式相同,但如果我尝试相同的模式,应用程序会在执行检查时死亡(在iOS上抛出EXC_BAD_ACCESS)。具体做法是:

if (BrandNewIdentifier) ... // blows up here

取而代之的是检查标识符的地址:

if (&BrandNewIdentifier) {
    printf("You got it!");
}

我可以看到逻辑:BrandNewIdentifier没有值,因此访问它会失败。但那么为什么这种语法适用于BrandNewFunc?我不应该被要求检查其地址吗?或者它实际上是否一致,还有一些我忽略的东西?

1 个答案:

答案 0 :(得分:2)

C标准的相关部分是第6.3.2.1节“左值,数组和函数指示符”。以下是关于功能的说法:

  

函数指示符是具有函数类型的表达式。除非它是sizeof运算符 65 或一元&运算符的操作数,否则函数指示符的类型为''函数,返回 type ' '被转换为一个表达式,其类型为''指向函数的指针 type ''。

     

[脚注65]因为没有发生这种转换,sizeof运算符的操作数仍然是函数指示符,并且违反了6.5.3.4中的约束[编辑:6.5.3.4中的约束说你可能没有将sizeof应用于函数指示符 - 这是语义错误]。

命名函数的标识符是最简单的“具有函数类型的表达式”。所以这意味着,如果foo已被声明为函数,则标识符foo计算为指向该函数的指针,除了,当它是{{1}的操作数时(在这种情况下,较大的表达式&计算为指向该函数的指针)或&foo的操作数(在这种情况下,较大的表达式sizeof会引发编译错误)

tl,dr:当sizeof(foo)是函数时,foofoo根据定义是等效的。这是功能的特殊规则。它与数组的特殊规则并不完全不同,数组也在许多情况下“衰减”到指针(该规则是我引用的一个段落)。

旁白:是的,这意味着函数调用运算符总是在指向函数的指针上运行。当&foo是指向函数的指针变量时,pfunc的处理方式就像读取(*pfunc)() ...或只是(&(*pfunc))()一样。