在未命名的命名空间中定义的C回调函数?

Joh*_*itb 6 c++ calling-convention linkage

我有一个使用C bison解析器的C++项目.C语法分析器使用函数指针的结构来调用函数,这些函数在生产被bison减少时创建正确的AST节点:

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

现在,在项目的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;
}
Run Code Online (Sandbox Code Playgroud)

现在我把它们放在其中的唯一原因extern "C"是因为我希望它们具有C调用约定.但最佳的是,我希望他们的名字仍然受到损害.它们永远不会从C代码中调用,因此名称重整不是问题.使它们受损会避免名称冲突,因为有些动作被称为error,并且C++回调函数具有丑陋的名称,如下所示只是为了避免与其他模块的名称冲突.

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

  /* ... */
}

a.error = &uglyNameError;
Run Code Online (Sandbox Code Playgroud)

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

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

有任何想法吗?我在寻找标准C++解决方案.

Han*_*ant 3

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

  • 啊,我可以把它设为“静态”。好主意,为什么我没有想到这一点:)我只想到了未命名的命名空间,但这不会对它们的链接产生任何影响,也不会防止“extern“C””函数的冲突。但“static”实际上可以工作!对于答案的其余部分:如果实现希望这样做,它可以对调用约定产生影响。我不想依赖任何特定的实现,所以我将它们设置为“extern "C"”。 (2认同)