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

时间:2010-05-09 10:52:09

标签: 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);
  /* ... */
};

现在,在项目的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 ++解决方案。

1 个答案:

答案 0 :(得分:3)

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