【问题标题】:C callback functions defined in an unnamed namespace?在未命名的命名空间中定义的 C 回调函数?
【发布时间】:2010-05-09 10:52:08
【问题描述】:

我有一个使用 C 野牛解析器的 C++ 项目。 C 解析器使用函数指针结构来调用函数,当产生式被野牛减少时,这些函数会创建适当的 AST 节点:

typedef void Node;
struct Actions {
  Node *(*newIntLit)(int val);
  Node *(*newAsgnExpr)(Node *left, Node *right);
  /* ... */
};

现在,在项目的 C++ 部分,我填写了这些指针

class AstNode {
  /* ... */
};
class IntLit : public AstNode { 
  /* ... */
};

extern "C" {
  Node *newIntLit(int val) {
    return (Node*)new IntLit(val);
  }

  /* ... */
}

Actions createActions() {
  Actions a;
  a.newIntLit = &newIntLit;
  /* ... */
  return a;
}

现在我将它们放在extern "C" 中的唯一原因是因为我希望它们具有 C 调用约定。但最理想的是,我希望他们的名字仍然被破坏。它们永远不会从 C 代码中按名称调用,因此名称修改不是问题。将它们弄乱可以避免名称冲突,因为某些操作被称为 error,并且 C++ 回调函数具有如下丑陋的名称,以避免与其他模块发生名称冲突。

extern "C" {
  void uglyNameError(char const *str) {
    /* ... */
  }

  /* ... */
}

a.error = &uglyNameError;

我想知道是否可以仅通过给函数类型 C 链接来实现

extern "C" void fty(char const *str);
namespace {
  fty error; /* Declared! But i can i define it with that type!? */
}

有什么想法吗?我正在寻找标准 C++ 解决方案。

【问题讨论】:

  • 你不能将 Bison 输出编译为 C++ 代码,从而完全避免这个问题吗?
  • @Konrad 我的同事说,bison C++ 模式不好用,所以我们用纯 C 做这部分,并把它抽象出来,所以和扫描仪一起组成了一个纯 C 库.

标签: c++ calling-convention linkage


【解决方案1】:

我不明白这个问题。 extern 关键字不影响调用约定,只是呈现给链接器的名称。用 C++ 编写的不是实例方法的函数仍然是 __cdecl,有或没有 extern "C"。此外,只要将 createActions() 保存在同一个源代码文件中,这些函数就不需要外部链接。您可以将它们声明为静态或将它们放在未命名的命名空间中以避免冲突。

【讨论】:

  • 啊,那我可以做static。好主意,我为什么没想到 :) 我只想到了未命名的命名空间,但这不会对它们的链接做任何事情,也不会防止 extern "C" 函数的冲突。但是static 真的可以工作!对于您答案的其余部分:如果实现希望这样做,它可以对调用约定产生影响。我不想依赖任何特定的实现,所以我把它们设为extern "C"
猜你喜欢
  • 1970-01-01
  • 2016-03-29
  • 2013-05-17
  • 2013-03-25
  • 2016-10-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多