【问题标题】:Is it possible to prevent POSIX symbol name pollution in Objective-C?是否可以防止 Objective-C 中的 POSIX 符号名称污染?
【发布时间】:2018-04-16 01:13:45
【问题描述】:

我在 Xcode/Objective-C 中遇到了一些意想不到的行为。我知道可能不建议这样做,但如果我想在 .m 文件中创建自己的struct in_addr,似乎我做不到。这意味着 Objective-C 中的命名空间和符号污染有些奇怪。这似乎适用于许多其他网络类型,也许也适用于其他 POSIX-y 事物。

我想出了一个非常基本的示例来演示这种行为。注意这个sn-p就是.m文件的全部内容。

#define _SYS_SOCKET_H_
#define _NETINET_IN_H_
#include <stdint.h>

struct in_addr {
  uint32_t foo;
};

这会产生构建错误Redefinition of 'in_addr'

这暗示了关于 Objective-C 的一些相当奇怪的事情。首先,我不希望&lt;stdint.h&gt; 引入任何网络类型。但即使允许它可能,首先定义_NETINET_IN_H_ 应该会阻止struct in_addr 的定义。然而即使如此,这段代码仍然拒绝构建。

是否有可能以某种方式放弃这种强制符号可见性?无论如何,是否有包含符号的列表?这种行为有充分的理由吗?

编辑:更奇怪的是,如果我删除 &lt;stdint.h&gt; 并将 uint32_t 更改为 int,这实际上会编译。

【问题讨论】:

    标签: objective-c


    【解决方案1】:

    如果您进入报告导航器并阅读clang 工具发出的完整错误,您会看到一个重要提示:

    In module 'Darwin' imported from /Users/csrstka/Desktop/asdfasdf/asdfasdf/main.m:1:
    /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/netinet/in.h:302:12: note: field has name 's_addr' here
        in_addr_t s_addr;
    

    如您所见,现有的in_addr 来自Darwin 模块,由于stdint.h#includeDarwin 模块的一部分而隐式导入。如果你在 Xcode 中转到 Product > Perform Action > Preprocess,你可以看到这一点——而不是复制你导入的所有标题,只有一行关于导入 Darwin.C.stdint

    基本上,模块有几个用途;它们通过减少冗余编译任务来缩短编译时间,并且防止人们像您尝试做的那样通过#defines 弄乱库头文件。 ;-) 有关 Objective-C 模块、它们的工作原理以及它们背后的原理的更多信息,请参阅此链接:

    https://clang.llvm.org/docs/Modules.html#introduction

    您的问题特别感兴趣的是以下摘录:

    模块的主要用户级功能是导入操作,它提供对软件库 API 的访问。然而,今天的程序大量使用#include,假设所有这些代码都会在一夜之间改变是不现实的。相反,模块会自动将#include 指令转换为相应的模块导入。例如,包含指令

    #include &lt;stdio.h&gt;

    将自动映射到模块 std.io 的导入。即使在语言中有特定的导入语法,这个特殊的特性对于采用和向后兼容性都很重要:#include 到 import 的自动翻译允许应用程序获得模块的好处(对于所有启用模块的库),而不需要对应用程序本身。因此,用户可以轻松地将模块与一个编译器一起使用,而在其他编译器中退回到预处理器包含机制。

    后来:

    如果将模块的任何子模块导入程序的任何部分,则整个顶级模块都被认为是程序的一部分。因此,Clang 可以诊断在未导入子模块中声明的实体与在当前翻译单元中声明的实体之间的冲突,并且 Clang 可以根据来自未导入子模块的知识进行内联或去虚拟化。

    或者,如果您希望关闭它们并获得更传统的类似 C 的行为,您可以在 Xcode 的 Build Settings 中简单地将 Enable Modules (C and Objective-C) 设置为 No,或者如果您使用的是不带 -fmodules 标志的编译命令行。

    【讨论】:

    • 哇,我从没想到会是这样。不过,这似乎是一个奇怪的选择。它打破了你在 C 中所做的很多假设,即你只能得到你所包含的内容。是否有可能只获得部分模块?达尔文模块是全有还是全无?
    • @BrianArmstrong 根据我引用的第二段摘录,Darwin 模块确实是孤注一掷。这对于 Objective-C 的默认设置并不奇怪,因为大多数 Objective-C 应用程序都将导入 Foundation 模块(或 #import &lt;Foundation/Foundation.h&gt;,它做同样的事情),而且 Foundation 包括几乎所有这些东西在它自己的标题中。但是,如果这带来了问题,您可以通过关闭模块功能来获得传统的 C 行为。
    猜你喜欢
    • 2020-08-22
    • 2014-05-30
    • 2014-04-09
    • 2014-02-24
    • 2015-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-17
    相关资源
    最近更新 更多