以下の定義A
がB
によってを交換する:#defineとtypedefオペランドが逆になるのはなぜですか?
#define A B
をこのタイプB
の別名であることA
を定義するのに対し:
typedef B A;
なぜ?これはインコヒーレントではないですか?
以下の定義A
がB
によってを交換する:#defineとtypedefオペランドが逆になるのはなぜですか?
#define A B
をこのタイプB
の別名であることA
を定義するのに対し:
typedef B A;
なぜ?これはインコヒーレントではないですか?
簡単に言えば、次の変数宣言を考えてみます。
// declare a variable called "myInt" with type int
int myInt;
// declare a variable called "myDouble" with type double
double myDouble;
// declare a variable called "myLong" with type long
long myLong;
// declare a variable called "myFunc" with type pointer to function
void (*myFunc)(char*);
その後typedef
sは完璧な理にかなって:
// declare a type alias called "myInt" with type int
typedef int myInt;
// declare a type alias called "myDouble" with type double
typedef double myDouble;
// declare a type alias called "myLong" with type long
typedef long myLong;
// declare a type alias called "myFunc" with type pointer to function
typedef void (*myFunc)(char*);
マクロ、一方、関数スタイルの構文を取ることができます:
#define A(B, C) B, C
A(1, 2) // expands out to 1, 2
マクロの場合、「名前」の後に続く「定義」makもっと意味がある。
(これはところで、あまりにもC++にも適用されます。)
A
(typedef
)は、複数の記号、たとえば、 typedef int Integer, *PInteger;
。 これは変数の定義方法(int var, *pvar;
)と一貫しています。
はい、typedefの構文は、私も少し捨ててしまう傾向があります。私はあなたの質問が苦情の多くであると仮定します.Cは40歳近くですが、typedefの構文が変わるとは思わないでしょうか?
もちろんnot = D – fouronnes
はい、マクロはかなり混乱しています。
typedef
言語の残りのほとんどが完了した後、かなりの間、言語に追加されました。これは、ストレージ・クラスと同じシンタックスを使用し:
static int x;
extern int y;
typedef int z;
これらx
、y
とz
すべてint
ものとして定義 - エイリアスのために基本的に差がx
とy
タイプint
のオブジェクトであるということである、とz
をint
それ自身。
このように、typedef
は適切な言語で適切に適合し、実際には「奇妙な人」のプリプロセッサです(通常通り)。同時に、言語の残りの部分も同様に変わるべきだと主張することができます。それは些細な例については、違いの多くを作るわけではありませんが、私はあなたがより多くを扱う場合は特に、これは読むためにかなり単純だと思う
type
z = integer;
var
x : integer;
:ちょうど明白な例のために、パスカルは、およそ物事の順序を逆転させました複雑な宣言。しかし、Pascalは(ほとんど)好意を失い、Javaのような新しい言語はC構文のこの特定の部分を保持しています(つまり、C言語の部分は変更の必要性が最も高い部分です) 。
+1:宣言を宣言するキーワードの概念を覚えておくとよいでしょう。キーワード/演算子を使わずに、構文的順序だけで呼び出される言語構成を導入する前に、常に2回考えてください。 – Potatoswatter
なぜマクロ(Cプリプロセッサを暗示している)が混乱していると思いますか?それはC言語と比べていくつかの面で全く異なっていますか?絶対に(例えば、早期結合と比較して後期結合)。完全に学ぶのは難しいでしょうか?はい、できます。しかし、混乱ですか?私には分かりません。だからあなたは "混乱"の意味を詳しく説明することができますか? – hlovdal
@hlovdal:最も顕著な問題のいくつかは、1)スコープの欠如、2)デバッガに利用できない情報、3)非常にエラーが発生しやすい(例えば、複数の評価された引数)などです。彼らは*まれに*利用可能な最高のソリューションです。 –
Typedefは、storage class specifier
グループの言語構文の観点から、extern
とstatic
(*)と一緒に使用されているため、typedefの配置は同じです。それは明らかにこのグループに属していませんが、私はそれがおそらく最も誤って配置されていない場所だったと思います。
(*) ストレージクラスにもauto
とregister
が含まれていますが、それ以上使用するものはありません。
なぜ私は言語の意思決定に関係するのか分かりませんが、typedefは私にとって意味があります。
typedef
指定子は言語の一部です。タイプをある種の名前にエイリアスする方法として役立ちます。変数の宣言で型が何であるかは、常にインライン展開できます。 typedef
ミラーの代わりに型に変数を宣言するの、あなたがタイプの名前を宣言している除いて、この使用を使用して
struct arr { int len; char *chars; } name;
struct arr another_name;
。それは言語が特定の構造を表し、それを宣言するより自然な方法を使用することができる方法にバインドされていないので
typedef struct { int len; char *chars; } arr;
arr name;
arr another_name;
#define
ディレクティブは、プリプロセッサのではなく、言語の一部です。
プリプロセッサとコンパイラは実際には独自の構文を持つ2つの異なるプログラムであるためです。プリプロセッサと他の言語とをあまり混乱させないで組み合わせることができました(実際には、dBase IIIプログラムとAutoLISPでcpp
を使用していました。 他の人が既に指摘したように、typedef
はCの宣言システムの構文に従い、#define
は簡単な直進宣言である。
PS:私は彼らが全く違っていて、非常に異なる目的のために使用されていることを知っています。しかし、個人的には、typedefは別の方法であったはずです。 – fouronnes
それがどんな慰めでもあれば、Ken Thompsonは同じことを考えています。 Goでは、型エイリアスだけを生成する 'typedef'に直接相当するものはありませんが、古い型から新しい型を作成する方法は' type NewType OldType'です。彼とDennis Ritchieが、Goが明示的に類似しているという構文の決定をCとは一線を画して議論するのだろうかと思います.Goの宣言の順序は基本的に「逆の方法」です:-) –