6

Cバイソンパーサーを使用する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!? */
}

何か案は?Standard-C++ソリューションを探しています。

4

1 に答える 1

3

問題はありません。externキーワードは呼び出し規約に影響を与えず、リンカに提示される名前だけに影響します。インスタンスメソッドではないC++で記述された関数は、extern "C"の有無にかかわらず、依然として__cdeclです。さらに、createActions()を同じソースコードファイルに保持している限り、これらの関数は外部リンクを必要としません。衝突を避けるために、静的に宣言するか、名前のない名前空間に配置することができます。

于 2010-05-09T12:45:12.737 に答える