函数名称和原型中的斜线和点?
我是C的新手,看着Go的源代码树,我发现了这个:
https://code.google.com/p/go/source/browse/src/pkg/runtime/race.c
void runtime∕race·Read(int32 goid, void *addr, void *pc); void runtime∕race·Write(int32 goid, void *addr, void *pc); void runtime·raceinit(void) { // ... }
斜线和点(·)是什么意思? 这是有效的C吗?
重要更新:
最终的答案肯定是你在golang-nuts邮件列表中从 Go作者之一Russ Cox那里得到的答案 。 也就是说,我将在下面留下我之前的一些注释,它们可能有助于理解一些事情。
另外,通过阅读上面链接的这个答案,我相信
∕
“伪斜杠”现在可以转换为常规/
斜杠(就像middot被翻译成点)在较新版本的Go C编译器中,而不是我测试的那个下面 – 但我没时间核实。
该文件由Go Language Suite的内部C编译器编译 ,该编译器源自Plan 9 C编译器(1) (2) ,并且与C标准有一些差异 (主要是扩展,AFAIK)。
其中一个扩展是,它允许标识符中包含UTF-8字符。
现在,在Go Language Suite的C编译器中,middot字符(·)以特殊方式处理,因为它被转换为目标文件中的常规点(。),由Go Language Suite的内部链接器解释为命名空间分隔符字符。
例
对于以下文件
example.c
(注意:它必须保存为没有BOM的UTF-8):void·Bar1(){} void foo·bar2(){} void foo / baz·bar3(){}内部C编译器生成以下符号:
$ go工具8c example.c $ go tool nm example.8 T“”。巴1 T foo.bar2 T foo / baz.bar3现在,请注意我给了
·Bar1()
一个大写·Bar1()
B
这是因为这样,我可以使它对常规Go代码可见 – 因为它被转换为与编译以下Go代码所产生的完全相同的符号:包装示例 func Bar1(){} // nm将显示:T“”。Bar1
现在,关于你在问题中命名的function,这个故事在兔子洞里走得更远。 我不太确定我是不是就在这里,但我会根据我的知识来解释。 因此,低于这一点的每个句子应该被理解为好像它最后写的是“ AFAIK ”。
因此,更好地理解这个难题所需的下一个缺失的部分是更多地了解奇怪的""
命名空间,以及Go套件的链接器如何处理它。 ""
命名空间是我们可能想要称之为“空”的(因为""
对于程序员来说意味着“空字符串”)命名空间,或者更好,称为“占位符”命名空间。 当链接器看到导入如下:
import examp "path/to/package/example" //... func main() { examp.Bar1() }
然后它需要$GOPATH/pkg/.../example.a
库文件,并且在导入阶段使用path/to/package/example
替换每个""
。 所以现在,在链接的程序中,我们将看到如下符号:
T path / to / package / example.Bar1
根据我的Javascript控制台,“·”字符是\xB7
。 “/”字符是\x2215
。
该点落在C99标准列表的附录D中,哪些特殊字符在C源中作为标识符有效。 斜杠似乎没有,所以我怀疑它是通过#define或预处理器魔法用作其他东西(也许是命名空间)。
这可以解释为什么点存在于实际的函数定义中,但斜杠不是。
编辑:检查此答案以获取一些其他信息。 GCC的实现可能只允许使用unicode斜杠。
看来这不是标准C,也不是C99。 特别是,即使在C99模式下, gcc
和clang
抱怨这个点。
此源代码由第9部分编译器套件(特别是OS X上的./pkg/tool/darwin_amd64/6c)编译,由Go构建系统引导。 根据该文档 ,第8页的底部,Plan 9及其编译器根本不使用ASCII,而是使用Unicode。 在第9页的底部,它声明任何具有足够高代码点的字符都被认为在标识符名称中有效。
根本没有预处理魔法 – 函数的定义与函数声明不匹配,因为它们是不同的函数。 例如, void runtime∕race·Initialize();
是一个外部函数,其定义出现在./src/pkg/runtime/race/race.go; 同样适用于void runtime∕race·MapShadow(…)
。
稍后出现的函数, void runtime·raceinit(void)
,是一个完全不同的函数,它实际上调用了runtime∕race·Initialize();
。
使用最初为plan9开发的C编译器编译go编译器/运行时。 当你从源代码构建时,它将首先构建plan9编译器,然后使用它们构建Go。
plan9编译器支持unicode函数名[1],Go开发人员在其函数名中使用unicode字符作为伪名称空间。
[1]看起来这可能实际上符合标准: g ++ unicode变量名,但gcc不支持unicode函数/变量名。