【问题标题】:Slashes and dots in function names and prototypes?函数名称和原型中的斜线和点?
【发布时间】:2012-11-08 16:18:59
【问题描述】:

我是 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 吗?

【问题讨论】:

  • 我不知道它们是什么,但它是无效的(标准)C.

标签: c go notation


【解决方案1】:

重要更新:

The ultimate answer is certainly the one you got from Russ Cox,Go 作者之一,在 golang-nuts 邮件列表中。也就是说,我将在下面留下一些我之前的笔记,它们可能有助于理解一些事情。

另外,通过阅读上面链接的这个答案,我相信 "pseudo-slash" 现在也可以在较新版本的 Go C 编译器中翻译成常规的 / 斜杠(就像中点被翻译成点一样)比我在下面测试的那个 - 但我没有时间验证。


该文件由 Go Language Suite's internal C compiler 编译,它源自 Plan 9 C 编译器(1)(2)has some differences(主要是扩展,AFAIK)到 C 标准。

其中一个扩展是,它允许在标识符中使用 UTF-8 字符。

现在,在 Go 语言套件的 C 编译器中,中间点字符 (·) 以特殊方式处理,因为它在目标文件中被翻译成常规点 (.),由 Go 语言套件的内部链接器解释作为命名空间分隔符。

示例

对于以下文件example.c(注意:必须保存为不带BOM的UTF-8):

无效·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 代码:

封装示例 func Bar1() {} // nm 将显示:T "".Bar1

现在,关于您在问题中提到的函数,故事更深入了兔子洞。我不太确定我是否在这里,但我会尝试根据我所知道的进行解释。因此,这一点以下的每个句子都应该像在末尾写上“AFAIK”一样阅读。

所以,为了更好地理解这个难题,下一个缺失的部分是更多地了解奇怪的 "" 命名空间,以及 Go 套件的链接器如何处理它。 "" 命名空间是我们可能想要称为“空”(因为"" 对程序员来说意味着“空字符串”)命名空间,或者更好的是“占位符”命名空间。当链接器看到这样的导入时:

import examp "path/to/package/example"
//...
func main() {
    examp.Bar1()
}

然后它获取$GOPATH/pkg/.../example.a 库文件,并在导入阶段动态替换每个""path/to/package/example。所以现在,在链接的程序中,我们会看到这样的符号:

T 路径/to/package/example.Bar1

【讨论】:

  • @Tom:顺便说一句,AFAIK 如果您愿意,您可以更改接受的答案;)
【解决方案2】:

go 编译器/运行时是使用最初为 plan9 开发的 C 编译器编译的。当你从源代码构建 go 时,它会首先构建 plan9 编译器,然后使用它们来构建 Go。

plan9 编译器支持 unicode 函数名 [1],Go 开发人员在其函数名中使用 unicode 字符作为伪命名空间。

[1] 看起来这实际上可能符合标准:g++ unicode variable name 但 gcc 不支持 unicode 函数/变量名称。

【讨论】:

    【解决方案3】:

    这似乎不是标准的 C,也不是 C99。特别是,gccclang 都抱怨这个点,即使在 C99 模式下也是如此。

    此源代码由第 9 部分编译器套件(特别是 OS X 上的 ./pkg/tool/darwin_amd64/6c)编译,该套件由 Go 构建系统引导。根据第 8 页底部的this document,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();

    【讨论】:

    • 谢谢,完全错过了。很好的答案。
    【解决方案4】:

    根据我的 Javascript 控制台,“·”字符是 \xB7。 “∕”字符是\x2215

    点位于C99 standard附录 D 中,列出了哪些特殊字符在 C 源代码中可用作标识符。斜线似乎没有,所以我怀疑它通过#define 或预处理器魔术被用作其他东西(可能是命名空间)。

    这可以解释为什么在实际的函数定义中存在点,而斜线却没有。

    编辑:查看This Answer 了解更多信息。 GCC 的实现可能只允许使用 unicode 斜杠。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-07-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-05-28
      相关资源
      最近更新 更多