代码之家  ›  专栏  ›  技术社区  ›  Johannes Schaub - litb

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

  •  6
  • Johannes Schaub - litb  · 技术社区  · 14 年前

    我有一个C++项目,它使用一个C BySon解析器。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 回复  |  直到 14 年前
        1
  •  3
  •   Hans Passant    14 年前

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