函数名称和原型中的斜线和点?

thw*_*hwd 18 c notation go

我是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)
{
    // ...
}
Run Code Online (Sandbox Code Playgroud)

斜线和点(·)是什么意思?这是有效的C吗?

aka*_*vel 19

重要更新:

最终的答案肯定是你在golang-nuts邮件列表中 Go作者之一 Russ Cox那里得到的答案.也就是说,我将在下面留下一些早期的注释,它们可能有助于理解一些事情.

另外,通过阅读上面链接的这个答案,我相信在新版本的Go C编译器中,?"伪斜杠"现在也可以转换为常规/斜杠(就像middot被翻译成点),而不是我在下面测试的版本 -但我没时间核实.


该文件由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 tool 8c example.c
$ go tool nm example.8
 T "".Bar1
 T foo.bar2
 T foo?baz.bar3

现在,请注意我给了·Bar1()一个资本B.这是因为这样,我可以使它对常规Go代码可见 - 因为它被转换为与编译以下Go代码所产生的完全相同的符号:

package example
func Bar1() {}  // nm will show:  T "".Bar1

现在,关于你在问题中命名的功能,这个故事在兔子洞里走得更远.如果我就在这里,我不太确定,但我会根据我的知识来解释.因此,低于这一点的每个句子应该被理解为好像它最后写有" AFAIK ".

因此,需要更好地理解这个难题的下一个缺失的部分是了解更多关于奇怪""名称空间的内容,以及Go套件的链接器如何处理它.该""命名空间是什么(因为我们可能要调用一个"空" ""一个程序员是指"空字符串")命名空间,或者也许更好,一个"占位符"命名空间.当链接器看到导入如下:

import examp "path/to/package/example"
//...
func main() {
    examp.Bar1()
}
Run Code Online (Sandbox Code Playgroud)

然后它需要$GOPATH/pkg/.../example.a库文件,并且在导入阶段,每次都""使用替换path/to/package/example.所以现在,在链接的程序中,我们将看到如下符号:

 T path/to/package/example.Bar1


Joh*_*ter 8

"·"字符是 \xB7根据我的Javascript控制台."/"字符是\x2215.

该点落入附件d C99标准列表的哪些特殊字符在C源中作为标识符有效.斜线似乎没有,所以我怀疑它是通过#define或预处理器魔法用作其他东西(也许是命名空间).

这可以解释为什么点存在于实际的函数定义中,但斜杠不是.

编辑:检查此答案以获取一些其他信息.GCC的实现可能只允许使用unicode斜杠.


use*_*136 5

看来这不是标准C,也不是C99.特别是,它都gccclang抱怨点,甚至在C99模式下.

此源代码由第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();.