我在Xcode / Objective-C中遇到了某种意外的行为。我知道可能不建议这样做,但是如果我想struct in_addr
在.m文件中创建自己的文件,似乎不可以。这意味着Objective-C中的名称空间和符号污染有些奇怪。这似乎适用于许多其他网络类型,也可能适用于其他POSIX-y。
我想出了一个非常基本的示例来演示此行为。请注意,此代码段是.m文件的全部内容。
#define _SYS_SOCKET_H_
#define _NETINET_IN_H_
#include <stdint.h>
struct in_addr {
uint32_t foo;
};
这产生了构建错误Redefinition of 'in_addr'
。
这意味着关于Objective-C的一些相当奇怪的事情。对于初学者,我不希望<stdint.h>
引入任何网络类型。但是即使允许,首先定义也_NETINET_IN_H_
应阻止的定义struct in_addr
。但是,即使如此,该代码仍拒绝构建。
是否有可能以某种方式放弃这种强制的符号可见性?是否有包含的符号列表?这种行为是否有充分的理由?
编辑:陌生人仍然,如果我删除<stdint.h>
并将其更改uint32_t
为int
,这实际上可以编译。
如果进入“报表”导航器并阅读该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
模块,由于模块的一部分,您#include
的隐含导入。如果您转到Xcode中的产品>执行操作>预处理,则会看到此内容-而不是复制已导入的所有标头,只有一行关于import 。stdint.h
Darwin
Darwin.C.stdint
基本上,模块有一些用途。它们通过减少多余的编译任务来缩短编译时间,并且防止人们通过#define
s弄乱您的库标头,就像您尝试做的那样。;-)有关Objective-C模块,其工作方式以及其背后的原理的更多信息,请参见以下链接:
https://clang.llvm.org/docs/Modules.html#introduction
您的问题特别有趣的是以下摘录:
模块的主要用户级别功能是导入操作,该操作提供对软件库API的访问。但是,当今的程序广泛使用#include,并且假设所有这些代码都会在一夜之间发生更改是不现实的。相反,模块会自动将#include指令转换为相应的模块导入。例如,include指令
#include <stdio.h>
将自动映射到模块std.io的导入。即使使用该语言的特定导入语法,此特定功能对于采用和向后兼容性也很重要:#include自动转换为导入使应用程序能够获得模块的好处(对于所有启用了模块的库),而无需更改应用程序本身。因此,用户可以轻松地在一个编译器中使用模块,而回退到其他编译器的预处理器包含机制。
然后:
如果将模块的任何子模块导入程序的任何部分,则整个顶级模块都被视为程序的一部分。结果,Clang可能会诊断未导入的子模块中声明的实体与当前翻译单元中声明的实体之间的冲突,并且Clang可能会基于未导入的子模块中的知识进行内联或虚拟化。
或者,如果您希望关闭它们并获得更传统的类似C的行为,则可以Enable Modules (C and Objective-C)
在Xcode的Build Settings中简单地设置为No,或者-fmodules
如果使用命令行,则不带标志即可进行编译。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句