sizeofスタイル:sizeof(type)またはsizeof変数?


22

sizeofメモリ関連の操作(in memsetやなどmalloc)に使用する2つのスタイルを見てきました。

  • sizeof(type)、そして
  • sizeof variable または sizeof(variable)

どちらを好むか、2つのスタイルを組み合わせて使用​​しますか。また、各スタイルをいつ使用しますか。各スタイルの長所と短所、およびそれらを使用するときは何ですか?

例として、一方のスタイルが役立ち、もう一方のスタイルが役立たない次のような状況を見ることができます。

ポインターの間接指定が間違っている場合:

type *var;
...
memset(var, 0, sizeof var);    /* oops */

タイプが変更されたとき:

new_type var;    /* changed from old_type to new_type */
...
memset(&var, 0, sizeof(old_type));    /* oops */

回答:


30

私はperfer sizeof(variable)オーバーsizeof(type)。考慮してください:

int a1;
float a2;
memset(&a1,0,sizeof(a1));
memset(&a2,0,sizeof(a2));

int a1;
float a2;
memset(&a1,0,sizeof(int));
memset(&a2,0,sizeof(float));

最初のケースでは、適切なサイズがに渡されていることを簡単に確認できmemsetます。2番目のケースでは、一貫性を保つために、上部と下部のセクションを常に確認する必要があります。


4
また、変数の型を変更する場合、その型を変更する必要があると想定するコード。型への依存をできるだけ少なくして正しいコードを作成することが望ましいと思います。(私は当時の大きな16ビットから32ビットへの変換プロジェクトの影響を受けています。)
ロボット

これは、typedefを作成することは一般的ではないが、char array [MAX_SIZE]のようなものを使用するC配列で作業するのに適しています。
マッテンツ

@ vy32:間違った1: "sizeof(array)は配列のサイズを返さない...配列へのポインタのサイズ" - array本当にC配列の場合sizeof(array)、配列要素を格納するのに必要なバイト数を返す。arrayが減衰C配列の最初の要素へのポインターである場合、ステートメントは保持されます。Cの配列を関数の引数として渡すと、関数内のポインターのように見えます。サイズのように、配列であることを証明するすべての情報が失われます。それが腐敗している理由です。間違った例2: 「配列は実際にはCには存在しません。...単にポインターの構文糖衣です。」
ヨハンゲレル14年

9

(常に)好みは、できるだけ直接あなたの意図を反映することです。

既存の変数のメモリに対して動作するつもりですか?その場合は、を使用しますsizeof(variable)。これは、変数自体のメモリであることができることを可能な限り詳しく示しているためです。

たとえば、新しいインスタンスに割り当てるメモリ量を決定するために、型に対して何らかの計算を実行するつもりですか?その場合は、を使用しますsizeof(type)

つまり、私は好む

struct foo *bar;
bar = (struct foo *) malloc(sizeof(struct foo));

以上

bar = (struct foo *) malloc(sizeof(*bar));

後者の場合、まだ存在しない変数にアクセスしようとしているように見えます。

一方、私は好む

char Buffer[256];
memset(Buffer, 0, sizeof(Buffer));

以上

char Buffer[256];
memset(Buffer, 0, 256 * sizeof(char));

変数の内容をゼロで埋めることが明確に意図されているため、操作対象の変数です。ここで、タイプメタデータを使用しようとすると混乱するだけです。



私はいつもやりますが、それは個人的な好みの問題です。私はと考えているvoid *のは、自動的に設計ミスであることを他のポインタ型にキャストされています。
エイダンカリー

3

私は非常に好むだろうsizeof(type)超えますsizeof variable。型についてもっと心配し、より多くの変更を行うことを強制しますが、Cのバグの最も一般的な原因の1つであるポインター間接化の間違いを避けるのに役立ちます。

タイプ入力sizeof(type)が変更されるバグについてはあまり心配しません。変数の型を変更するたびに、クイックスキャンを実行して、その変数が使用されている場所と、sizeof(type)ステートメントを変更する必要があるかどうかを確認する必要があります。常にこれが間違っている可能性はありますが、ポインターの間接指定の間違いよりもリスクがはるかに低くなります。

sizeof variable配列の利点の1つですが、実際には、配列をfirst / lenのペアとして渡す方がはるかに一般的であることがわかりました(この場合は長さを使用するだけでなく)。また、この例のように、配列/ポインターの減衰:

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
  memcpy( mat, src, sizeof( src ) );    /* NOT the same as 3*3*sizeof(float) */
}

2
「その変数がどこで使用されているかを確認するためのクイックスキャン....常にこれが間違っている可能性があります」-私にとって、これはsizeof(type)を行うことの最大の危険です。この危険の最終結果は、すべてがまだコンパイルされる可能性があり、1つのミスを犯したとしても、キャッチするまでに1年以上、ランダムなクラッシュとバッファ破損が発生する可能性があるためです。そして、この質問と「ポインターの間接指定の間違い」との間に関係を作ることができませんでした(明らかに、質問ごとの私の時間枠は約30秒です)。
-DXM

@DXM sizeofオペランドを使用すると、値の場合はsizeof var; ポインターの場合はsizeof *var。これも人々が間違っている可能性があるものであり、コンパイラーは文句なしに喜んでそれを受け入れます。sizeof(type)フォームの間違いよりも、これらの間違いを見つけるのははるかに難しく、より一般的であると私は主張します。
コンガスボン

1
あなたの両方の権利-Cの型とsizeof演算子は根本的に壊れており、信頼できるものになることはありません。プログラマが修正できるので、あなたは何もしません。
-mattnz

C投稿にタグが付けられているので、Cコードを投稿するほうがC ++コードが好むより有益ですmat3_t::mat3_t(...)
chux-モニカの復活

0

目的は、冗長性を削除することです。変数に関連する操作にsizeofを使用する場合、明らかにそれをsizeofに反映する必要があります。はい、最初の例のように混乱させることができますが、治療法はタイプを使用するのではなく、* var、目的に正しく一致するものです。

このような問題を軽減するために、ネイキッドサイズオブではなく、ユースケース用にトレーニングされたマクロ、テンプレート、および同様のツールを使用するのが一般的です。

ネイキッドmemsetの代わりに排他的に使用されるCLEARマクロを参照してください。間接的なタイプミスの場合、または構造体のコンテンツがベクトルまたは文字列を取得した場合に、お尻を数回保存しました...


そのようなマクロは、Cのマクロプログラミングに悪い名前を与えたものです……
mattnz

@mattnz:より良い代替案を示してください。実際に動作するプログラムを作成するよりも抽象的なことを話す方が簡単です
バログパル

1
リンクされたマクロはC ++であり、この投稿には 'C'(異なる言語です)というタグが付けられています。Adaが私の提案です。
-mattnz

@mattnz:同じトピックがCに対して同様の方法で実施する方法を示しています。あなたはその点を見逃しているように見えます。Btwの方法も読みやすい。
バログパル

0

ビジネスロジックは選択を定義します。

  1. コードが特定の変数を参照し、この変数なしではコードが意味をなさない場合-選択してください sizeof(var)

  2. 特定のタイプの変数セットを処理するコードを選択する場合は、を選択しますsizeof(type)。通常、typedefこれは、タイプに基づいて異なる方法で処理する多くの変数を定義している場合(シリアル化など)に必要です。これらの変数のどれが将来のコードバージョンに残るかわからない場合があるため、引数として型を選択することは論理的に正しいです。そのように変更してもtypedef、行のサイズには影響しません。


-1

目的によっては、sizeof(variable)が最適なソリューションになる場合があります。そのようにして、必要に応じて、変数のタイプのすべてのエントリを修正せずに変数のタイプを変更できます。しかし、これもまたあなたの目的次第です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.