4

重複の可能性:
型と同じ型のポインターをtypedefする正しい方法は何ですか?

最近、プロジェクトでLibxml2を使用していますが、次のようなtypedefが使用されていることに気付きました。

typedef struct _xmlNode xmlNode
typedef xmlNode * xmlNodePtr

最初のtypedefの利点は明らかです。ただし、xmlNode*に代替名を割り当てる理由がわかりません。私にとっては、xmlNodePtrを使用するよりもxmlNode *を使用する方が明示的で読みやすいです何かが足りない可能性があります。

このtypedefはどのような問題を解決し、どのようなメリットをもたらしますか?

4

4 に答える 4

2

C API は多くの場合、不透明なハンドルを提供します。これにより、コンシューマーはそれらが何であるかを尋ねたり、内部を突こうとしたりすることを思いとどまらせます。これらのハンドルがポインターであるという事実は重要ではなく、消費者にとって重要ではありません。

たとえば、ハンドルを定義して C++ バインディングを記述することは完全に可能です。

typedef void * MyHandle;

ここで、至福の C コンシューマーにいくつかの関数を与えます。

MyHandle create_gizmo();
void destroy_gizmo(MyHandle);
int do_magic(MyHandle, int, int);

そのような単純な。ユーザーはすぐにそれを使用する方法を確認します。

#include "MagicAPI.h"

MyHandle h = create_gizmo();

submit_result(do_magic(h, 12, 91));

destroy_gizmo(h);

そして、C++ ライブラリの開発者は、ハンドルをアンラップし、API 関数を設定するだけです (もちろん、宣言されていますextern "C")。

#include "MagicAPI.h"
#include "SuperGizmo.hpp"

MyHandle create_gizmo() { return static_cast<MyHandle>(new SuperGizmo); }

void destroy_gizmo(MyHandle h) { delete static_cast<SuperGizmo *>(h); }

int do_magic(MyHandle h, int a, int b)
{
    return static_cast<SuperGizmo *>(h)->foo(a, b);
}
于 2012-09-17T21:05:58.510 に答える
1

一部の人々にとっては、名前に「ptr」を含む typedef は、通常のポインター構文を使用した宣言よりも読みやすく、「自然」です。書くのが好きなら

foo* p;

それ以外の

foo *p;

その場合、ポインター typedef は、特に書き込みエラーを回避するため、おそらくあなたにアピールします

foo* p, q;

あなたが意味したとき

foo *p, *q;

代わりに、あなたは書くことができます

fooptr p, q;
于 2012-09-17T21:05:24.687 に答える
1

この typedef はどのような問題を解決し、どのようなメリットをもたらすでしょうか?

私の意見では、オブジェクト ポインターの型定義は良くないので、行うべきではありません。

まず、宣言されたオブジェクトがポインター型であることを隠すことによって、C 言語の文法を変更します。

2 番目の型修飾子 (constおよびvolatile) は typedef を貫通できません。

あなたの例を挙げると:

typedef struct _xmlNode xmlNode;
typedef xmlNode * xmlNodePtr;

オブジェクトを宣言することは現在不可能であるため、ポインティング先はエイリアスconstを使用しています。xmlNodePtr

const xmlNodePtr xp;

手段xpではありconstません*xp

const xmlNode x = /* ... */;
const xmlNodePtr xp = &x;  // Error!

ちなみに、Linux カーネルのコーディング スタイルではtypedef、ポインターには使用しないことも推奨されています。

「構造体とポインターに typedef を使用するのは間違いです。」

于 2012-09-17T21:18:50.260 に答える
0

いくつかの違いがあります。

まず、1 行で複数の宣言を行う場合、次の 2 つのスニペットは同等です。

char *c1, *c2, *c3, *c4;

typedef char * charPtr;
charPtr c1, c2, c3, c4; // I don't need to repeat the unary * everywhere

これは、次のようなことをしようとすると意味論的な問題に遭遇する可能性があるため、部分的に役立ちます。

char * c1, c2, c3, c4; // declares one char pointer and three chars

第二に、関数ポインタ型の定義を大幅に簡素化できますが、これはほぼ無限の醜さと厄介さの可能性です。

float (*someCrazyFunction)(float(*)(), float) = foo; // WTF is this

typedef float (*crazyFunction)(float(*)(), float);
crazyFunction myCrazyFunction = foo; // easier to deal with

これは、この動作のすべてを示すイデオンです。

于 2012-09-17T21:23:11.773 に答える