配列/構造体のデフォルトで初期化された値について読んでいて、この質問があります:
とmemset(&mystruct, 0, sizeof mystruct)
同じmystruct = { 0 };
ですか?
そうでない場合、違いは何ですか?
memset(&mystruct、0、sizeof mystruct)はmystruct={0}と同じです。?
いいえ。
memset(&mystruct, 0, sizeof mystruct) ;
...実行中にmystructのデータをゼロに設定すると予想される関数を呼び出すようにコンパイラーに指示します。
mystruct = { 0 };
... setは、コンパイラがデータをゼロに設定するように設定します。これは、次のことを意味します。
おそらくコンパイラーはmemsetをコンパイル時の命令に最適化できることに注意してください(最初のバージョンを2番目のバージョンに置き換えるなどmemset
)が、ランタイムライブラリの関数であるため、言語固有ではなく、それに依存しません( Iただし、コンパイラライター/言語弁護士ではありません)。
C ++から来て、私自身の見解は、コンパイルでできることが多く、実行が始まる前にコンパイラがコンパイル時に知っているほど良いということです。コンパイラがコードを最適化したり、警告を生成したりできるようになります。エラー。
現在の場合、mystruct = { 0 };
aを初期化するために表記を使用することは、コンパイラーが文句を言わずにCで間違ったものを書くのが非常に簡単でstruct
あるため、memsetを使用するよりも常に安全です。memset
次の例は、コードが見た目とは異なることを簡単に実行できることを示しています。
// only the 1st byte will be set to 0
memset(&mystruct, 0, sizeof(char)) ;
// will probably overrun the data, possibly corrupting
// the data around it, and you hope, crashing the process.
memset(&mystruct, 0, sizeof(myLARGEstruct)) ;
// will NOT set the data to 257. Instead it will truncate the
// integer and set each byte to 1
memset(&mystruct, 257, sizeof(mystruct)) ;
// will set each byte to the value of sizeof(mystruct) modulo 256
memset(&mystruct, sizeof(mystruct), 0) ;
// will work. Always.
mystruct = { 0 } ;
これは完全に衒学的な答えですが、nullポインターの内部表現が、中括弧の初期化と0
の動作が異なることが保証されていないことを考えると(間違ったことをします)。とは言うものの、nullに対してすべて0ビット以外のパターンを持つというこの自由を取り入れた実装については聞いたことがありません。memset
memset
理論的には違いがあります。にパディングがある場合、イニシャライザはパディングを初期化する必要はありませんmystruct
。例えば:
int main(void)
{
struct mystruct {
char a;
int what;
} s = {0};
}
含まれる可能性があります:
00 xx yy zz 00 00 00 00
ここで、xx yyとzzは、スタック上の未定義のバイトです。コンパイラはそれを行うことができます。これは、すべての実用的な用語で、私はまだそれを行ったコンパイラに遭遇したことがないということです。ほとんどの正常な実装は、のようにそのケースを意味的に処理し memset
ます。
memset(&mystruct, 0, sizeof mystruct);
ステートメントです。mystruct
定義された場所だけでなく、表示されている場所であればいつでも実行できます。
mystruct = { 0 };
実際には構文エラーです。{ 0 }
は有効な式ではありません。
mystruct
(これはタイプのオブジェクトであると想定しますstruct foo
。)
あなたがおそらく考えているのは:
struct foo mystruct = { 0 };
ここ{ 0 }
で、は初期化子です。
コンパイラがそれをサポートしている場合は、次のように書くこともできます。
mystruct = (struct foo){ 0 };
ここ(struct foo){ 0 }
で、は複合リテラルです。複合リテラルはC99で導入されました。一部のCコンパイラ、特にMicrosoftはおそらくそれをサポートしていません。(struct foo)
(はキャスト演算子ではないことに注意してください。見た目は似ていますが、式や括弧で囲まれた型名が続きません。これは別個の構文構造です。)
コンパイラが複合リテラルをサポートしていない場合は、定数を宣言することで回避できます。
const struct foo foo_zero = { 0 };
struct foo mystruct;
/* ... */
mystruct = foo_zero;
そのため、構文と使用場所が異なります。セマンティックの違いもあります。
memset
呼び出しは、の表現を構成するすべてのバイトをmystruct
すべてゼロに設定します。これは非常に低レベルの操作です。
一方、初期化子は次のとおりです。
struct foo mystruct = { 0 };
の最初のスカラーサブコンポーネントを0に設定し、他のすべてのサブコンポーネントを静的オブジェクトとして初期化されたかのように、つまり0に設定します(同じことを行うためのよりクリーンな構文mystruct
があればいいのですが、ありません。 struct foo mystruct = { };
t。)
重要なのは、何かをに設定することは、0
その表現をall-bits-zeroに設定することと必ずしも同じではないということです。値0
は、スカラーサブコンポーネントごとに適切なタイプに変換されます。
整数の場合、言語はall-bits-zeroがの表現であることを保証します0
(ただし、必ずしも唯一の表現ではありません0
)。整数をに設定すると、整数がすべてビットゼロに設定される可能性が非常に高くなり0
ますが、他の表現に設定できる可能性があり0
ます。実際には、それは意図的にひねくれたコンパイラーでのみ起こります。
ポインターの場合、ほとんどの実装はnullポインターをall-bits-zeroとして表しますが、言語はそれを保証するものではなく、他の表現を使用する実際の実装があります。(たとえば、all-bits-1のようなものを使用すると、実行時にnullポインターの逆参照を検出しやすくなる可能性があります。)また、ポインターの種類によって表現が異なる場合があります。comp.lang.cFAQのセクション5を参照してください。
同様に、浮動小数点型の場合、ほとんどの実装は0.0
all-bits-zeroとして表されますが、言語標準はそれを保証しません。
呼び出しによってすべてのサブコンポーネントがゼロに設定されると想定するコードを書くことでおそらく逃げることができますがmemset
、そのようなコードは厳密には移植可能ではありません-マーフィーの法則は、おそらくコードを移植するときに、最も不便な瞬間に想定が失敗することを意味します重要な新しいシステムに。