检查 C 中外部定义的标识符是否存在
我在针对 iOS 进行 Objective-C 开发时遇到了这个问题,但这应该适用于使用 Mac OS X/iOS 链接器的任何 C/C++/Objective-C 代码。 另一个问题涵盖了该解决方案,但我感兴趣为什么。
假设我正在使用一个到定义常量的库的链接。在头文件中有一个这样的声明:
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 的情况下有效呢?难道我不应该也被要求检查它的地址吗?或者它实际上是一致的,而我忽略了一些东西?
I ran into this problem while developing in Objective-C for iOS, but this should apply to any C/C++/Objective-C code using the Mac OS X/iOS linker. The solution is covered by another question, but I'm interested in the why.
Let's say I'm using a linking to a library which defines a constant. In a header file there is a declaration like this:
extern char * const BrandNewIdentifier;
I want to compile my application and run it on a system with an earlier version of the library, where that constant has no definition, so to be safe I don't assume it has been defined.
Now, if there's a function that is only defined in the most recent version of the library, I can do this:
if (BrandNewFunc) {
BrandNewFunc("foobar", 42);
} else {
printf("Your system does not support some thing.");
}
Instead of containing the address of function code, BrandNewFunc
evaluates to NULL. I would think that the constant would behave the same way, but if I try the same pattern, the app dies while performing a check (throws EXC_BAD_ACCESS on iOS). Specifically:
if (BrandNewIdentifier) ... // blows up here
What works instead is checking the address of the identifier:
if (&BrandNewIdentifier) {
printf("You got it!");
}
I can see the logic: BrandNewIdentifier
has no value, so accessing it should fail. But then why does that syntax work in the case of BrandNewFunc
? Shouldn't I be required to check its address also? Or is it actually consistent, and there is something I've overlooked?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
C 标准的相关部分是第 6.3.2.1 节“左值、数组和函数指示符”。这是它关于函数的说法:
命名函数的标识符是最简单的“具有函数类型的表达式”。所以这意味着,如果
foo
已被声明为函数,则标识符foo
将计算为指向该函数的指针,除非当它是&
的操作数(在这种情况下,较大的表达式&foo
计算为指向该函数的指针)或sizeof
的操作数(在这种情况下,较大的表达式sizeof(foo)
会引发编译错误)。tl,dr:当
foo
是函数时,foo
和&foo
在定义上是等效的。这是函数的特殊规则。它与数组的特殊规则并不完全不同,数组在许多上下文中也会“衰减”到指针(该规则是我引用的规则的上一段)。旁白:是的,这意味着函数调用运算符始终对函数指针进行操作。当
pfunc
是函数指针变量时,(*pfunc)()
的处理方式就像读取(&(*pfunc))()
...或者只是pfunc()
。The relevant part of the C standard is section 6.3.2.1 "Lvalues, arrays, and function designators". Here's what it says about functions:
An identifier that names a function is the simplest sort of "expression that has function type". So what this means is, if
foo
has been declared as a function, the identifierfoo
evaluates as a pointer to that function, except when it's the operand of&
(in which case the larger expression&foo
evaluates as a pointer to that function) or the operand ofsizeof
(in which case the larger expression,sizeof(foo)
, provokes a compile error).tl,dr: When
foo
is a function,foo
and&foo
are equivalent by definition. This is a special rule for functions. It's not entirely unlike the special rule for arrays, which also "decay" to pointers in many contexts (that rule is one paragraph up from the one I quoted).Aside: Yes, this means that the function-call operator always operates on a pointer-to-function. When
pfunc
is a pointer-to-function variable,(*pfunc)()
is processed as if it read(&(*pfunc))()
... or justpfunc()
.