memsetでbzeroを使用する理由


156

私はこの前学期に受けたシステムプログラミングクラスで、基本的なクライアント/サーバーをCで実装する必要がありました。などの構造体sock_addr_inや文字バッファー(クライアントとサーバー間でデータを送受信するために使用)を初期化するときにそれらを使用するだけで初期化しbzeroないように指示しmemsetました。彼はなぜその理由を説明したことがなく、これに正当な理由があるかどうか私は知りたいですか?

私はここを参照してください:http : //fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdownこれbzeroはメモリをゼロにするだけなので、より効率的であるため、実行されるmemset可能性がある追加のチェックを実行する必要があります。それでも、memsetメモリのゼロ化に絶対に使用しない理由とは限りません。

bzeroは非推奨と見なされ、さらに標準のC関数ではありません。マニュアルによると、この理由のためにmemset推奨されbzeroます。では、なぜそれbzero以上に使いたいのでしょうmemsetか?効率を上げるためだけですか、それともそれ以上ですか?同様に、それが新しいプログラムにとって事実上好ましいオプションになっmemsetbzeroいることの利点は何ですか?


28
「memsetでbzeroを使用する理由」- しないでください。Memsetは標準ですが、bzeroは標準ではありません。

30
bzeroはBSDism()です。memset()はansi-cです。現在、bzero()はおそらくマクロとして実装されます。教授に自分のひげを剃り、いくつかの本を読んでもらいます。効率は偽の議論です。syscallまたはコンテキストスイッチは、数万のクロックティックを簡単に消費する可能性があり、1回のパスでバッファをバス速度で実行します。ネットワークプログラムを最適化する場合:システムコールの数を最小限に抑える(大きなチャンクの読み取り/書き込みにより)
wildplasser

7
memset「もう少しチェックが進んでいる」ために効率が少し低下する可能性があるという考えは、明らかに時期尚早の最適化のケースです。CPU命令を省略して得られるメリットが何であれ、移植性を損なう可能性がある場合は、その価値はありません。コード。bzero時代遅れであり、それはそれを使用しない十分な理由です。
dasblinkenlight 2013年

4
多くの場合、代わりに初期化子 `= {0}`を追加して、関数をまったく呼び出せません。これは、世紀の変わり目頃、Cがローカル変数の事前宣言を要求しなくなったときに、より簡単になりました。いくつかの本当に古い紙器とはいえ、まだ前世紀で立ち往生深いです。
MSalters 2015年

1
:@SSAnneいいえ、それは最も可能性の高い以下の答えの1で述べたように彼は、影響を受けたコースの推奨ブックから発信stackoverflow.com/a/17097072/1428743
PseudoPsyche

回答:


152

私が好むする理由は表示されませんbzero以上をmemset

memset一方で、標準C関数であるbzeroC標準関数ではありませんでした。その理由は、関数を使用してまったく同じ機能を実現できるためと考えられますmemset

効率性に関して、コンパイラーは定数が検出されたときに特定の実装に切り替えるgcc組み込み実装を使用してmemset0ます。glibc組み込みが無効になっている場合も同様です。


ありがとう。意味あり。memsetこの場合は常にそれを使用するべきだと確信していましたが、なぜそれを使用しなかったのか混乱しました。私の考えを明確にし、再確認してくれてありがとう。
PseudoPsyche 2013年

1
壊れたbzero実装で多くの問題がありました。アラインされていない配列では、指定された長さをオーバーシュートして、もう少しバイトをゼロにしていた。に切り替えた後、このような問題は発生しませんでしたmemset
rustyx 14

memset_sコンパイラがセキュリティ関連の目的(機密情報を含むメモリの領域を空白にするなど)のためにメモリを「スクラブ」する呼び出しを静かに最適化しないようにする場合は、どちらを使用するかを忘れないでください。平文パスワードなどの情報)。
クリストファーシュルツ

69

W.リチャードスティーブンスのUNIXネットワークプログラミングを使用した(または教師の影響を受けた)と思います。最新版でも、彼はのbzero代わりに頻繁に使用していmemsetます。この本はとても人気があるので、ネットワークプログラミングの慣用句になっていると思います。

は非推奨であり、移植性が低下するmemsetため、そのままbzero使用します。どちらか一方を使用することで実際に利益が得られるとは思えません。


4
あなたは正しいでしょう。このコースでは必須のテキストはありませんでしたが、シラバスをもう一度確認したところ、UNIXネットワークプログラミングはオプションのリソースとして実際にリストされています。ありがとう。
PseudoPsyche 2013年

9
それは実際にはもっと悪いです。POSIX.1-2001で廃止され、POSIX.1-2008で削除されました。
paxdiablo 2013

9
W.リチャードスティーブンスによるUNIXネットワークプログラミングの第3版の8ページを引用- 確かに、TCPv3の作者は、最初の印刷の10回のオカレンスで、2番目と3番目の引数をmemsetに交換するミスを犯しました。両方の発生が同じであるため、Cコンパイラーはこのエラーをキャッチできません...これはエラーであり、関数プロトタイプが使用されている場合、2つの引数をbzeroにスワップするとCコンパイラーによって常にキャッチされるため、bzeroを使用して回避できます。ただし、paxdiabloが指摘したように、bzeroは非推奨です。
アーロンニュートン

@AaronNewton、彼が言ったことを確認するので、あなたはそれをマイケルの答えに加えるべきです。
Synetech 2015

52

メモリをゼロに設定bzero()することmemset()に対して私が持っていると考える1つの利点は、間違いが発生する可能性が減ることです。

2回以上、次のようなバグに遭遇しました。

memset(someobject, size_of_object, 0);    // clear object

コンパイラーは文句を言わず(一部のコンパイラーでは警告レベルが上がる可能性があります)、その結果、メモリーがクリアされません。これはオブジェクトを壊さないので-それはそれをそのままにします-バグが明らかなものに現れないかもしれないかなりの可能性があります。

bzero()標準ではないという事実は軽微な刺激です。(FWIW、私のプログラムのほとんどの関数呼び出しが非標準であるとしても、私は驚かないでしょう。実際、そのような関数を書くことは私の仕事の一種です)。

ここの別の回答へのコメントで、Aaron Newtonは、StevensらによるUnix Network Programming、第1巻、第3版、セクション1.2(強調を追加)から以下を引用しました:

bzeroANSI C関数ではありません。これは、初期のバークレーネットワークコードから派生しています。それにもかかわらず、(3つの引数を使用するより)(2つの引数のみを使用して)覚えやすいmemsetため、テキスト全体でANSI C 関数の代わりに使用します。ソケットAPIをサポートするほとんどすべてのベンダーもを提供しており、そうでない場合は、ヘッダーにマクロ定義を提供します。bzeromemsetbzerounp.h

確かに、TCPv3の作者[TCP / IP Illustrated、Volume 3-Stevens 1996] memsetは、最初の印刷で2番目と3番目の引数を10回に交換するという間違いを犯しました。両方の引数が同じ型であるため、Cコンパイラはこのエラーをキャッチできません。(実際には、2番目の引数はintで、3番目の引数はですsize_t。これは通常unsigned intですが、指定された値0と16はそれぞれ、他のタイプの引数でも受け入れられます。)への呼び出しmemsetは、一部のソケット関数では、実際にはインターネットソケットアドレス構造の最後の8バイトを0に設定する必要があります。それでもエラーは発生しました。 bzeroなぜならbzero、関数のプロトタイプが使用されている場合、2つの引数の入れ替えは常にCコンパイラによってキャッチされるからです。

への呼び出しの大部分はmemset()メモリをゼロにすることでもあると思います。そのため、そのユースケースに合わせて調整されたAPIを使用してみませんか?

考えられる欠点bzero()は、コンパイラーがmemcpy()標準であるため、コンパイラーが最適化する可能性が高く、それを認識できるように作成されている可能性があることです。ただし、最適化された誤ったコードよりも正しいコードの方が優れていることに注意してください。ほとんどの場合、使用bzero()してもプログラムのパフォーマンスに大きな影響はありません。bzero()マクロまたはインライン関数になり、に展開されmemcpy()ます。


はい、私はこれがこのように教室の設定で作業するときの理由かもしれないと思います、それは学生にとって混乱を少なくするためです。しかし、私の教授はそうではなかったと思います。彼は非常に大きなRTFM教師でした。マニュアルで回答できる質問がある場合は、クラスのプロジェクターのマニュアルページを表示して表示します。彼はマニュアルが読まれるべきであり、あなたの質問のほとんどに答えるということを皆の心に染み込ませることについて非常にそうでした。他のいくつかの教授とは対照的に、私はこれに感謝しています。
PseudoPsyche 2013年

5
これは教室の外でもできる議論だと思います-本番コードでこのバグを見たことがあります。それは私が犯しやすい間違いとして私を襲う。また、memset()呼び出しの大部分は単にメモリのブロックをゼロにすることであると思いますbzero()。これは、のもう1つの議論だと思います。bzero()とにかく'b'は何を表していますか?
マイケルバー

7
+1。これmemsetは、「buffer、buffer_size」の一般的なパラメーターの順序に違反しているため、特にエラーが発生しやすいIMOになります。
jamesdlin 2013

Pascalでは、「fillchar」と呼ぶことでそれを回避し、charを取得します。ほとんどのC / C ++コンパイラは、これを取り上げます。コンパイラが「バイトが期待される場所に32/64ビットポインタを渡しています」と言わない理由を不思議に思って、コンパイラエラーであなたをしっかり蹴ります。
MOZ

1
@Gewureの2番目と3番目の引数の順序が間違っています。引用された関数呼び出しはまったく何もしません
Ichthyo 2018

4

bzeroとmemsetの引数について説明したかった。ltraceをインストールして、内部での動作を比較します。libc6(2.19-0ubuntu6.6)を使用するLinuxでは、行われる呼び出しは(を介してltrace ./test123)まったく同じです。

long m[] = {0}; // generates a call to memset(0x7fffefa28238, '\0', 8)
int* p;
bzero(&p, 4);   // generates a call to memset(0x7fffefa28230, '\0', 4)

私は、libc深い腸やカーネル/ syscallインターフェースの数に関係なく作業しているのでなければ、それらについて心配する必要はないと言われてきました。私が心配する必要があるのは、呼び出しがバッファをゼロにするという要件を満たすことだけです。他の人がどちらが好ましいかについて述べたので、ここで終了します。


これは、GCCの一部のバージョンがmemset(ptr, 0, n)表示されたときにコードを生成 し、bzero(ptr, n)インラインコードに変換できないために発生します。
zwol 2018年

@zwol実際にはマクロです。
SSアン

1
私のコンピューター上の@SSAnne gcc 9.3は、システムヘッダーのマクロからの助けなしに、この変換自体を実行します。extern void bzero(void *, size_t); void clear(void *p, size_t n) { bzero(p, n); }への呼び出しを生成しますmemset。(インクルードstddef.hのためにsize_t干渉する可能性が何かせず。)
zwol

4

おそらく使用すべきではありませんbzero。これは実際には標準のCではなく、POSIXのものでした。

また、「was」という単語は、POSIX.1-2001で廃止され、POSIX.1-2008でmemset との関係で削除されたため、標準のC関数を使用する方がよいでしょう。


標準Cとはどういう意味ですか?あなたはそれが標準のCライブラリに見つからないということですか?
Koray Tugay

@Koray、標準CはISO標準を意味し、はい、bzeroその一部ではありません。
paxdiablo 2015

いいえ、私はあなたがどんな基準で何を意味しているのかわかりません。ISO標準は標準Cライブラリを意味しますか?それは言語に付属していますか?私たちが知っている最小限のライブラリはそこにあるでしょうか?
Koray Tugay

2
@ Koray、ISOは、C標準を担当する標準化団体であり、現在の標準はC11、以前の標準はC99およびC89です。それらはCと見なされるために実装が従わなければならない規則を定めています。そのため、標準が実装がmemsetを提供する必要があると標準が言っている場合、それはあなたのためにあります。そうでなければ、それはC.ではありません
paxdiablo

2

memset関数の場合、2番目の引数はintで、3番目の引数はですsize_t

void *memset(void *s, int c, size_t n);

これは通常unsigned intですが、0 and 162番目と3番目の引数の値がそれぞれ16と0のように間違った順序で入力された場合、memsetへのこのような呼び出しは機能しますが、何もしません。初期化するバイト数はと指定されているため0です。

void bzero(void *s, size_t n)

関数プロトタイプが使用されている場合、bzeroへの2つの引数の交換は常にCコンパイラーによってキャッチされるため、このようなエラーはbzeroを使用することで回避できます。


1
このようなエラーは、呼び出しを単に「このメモリをこのサイズのこの値に設定する」と考える場合、またはプロトタイプを提供するIDEがある場合、または何をしているのかさえわかっている場合でも、memsetで回避できます。実行中:-)
paxdiablo 2015

同意しますが、この機能は、そのようなインテリジェントIDEがサポートで利用できなかったときに作成されました。
2015

2

つまり memset、それ以上のアセンブリ操作が必要になりbzeroます。

これはソースです:http : //fdiv.net/2009/01/14/memset-vs-bzero-ultimate-showdown


はい、それは私がOPで言及した1つのことです。私は実際にその正確なページにリンクしています。コンパイラの最適化によっては、それほど大きな違いはないようです。詳細については、ouahが承認した回答を参照してください。
PseudoPsyche 2014年

6
これは、memsetのゴミ実装の1つが遅いことを示しているだけです。MacOS Xおよびその他の一部のシステムでは、memsetは、使用しているプロセッサーに応じてブート時にセットアップされるコードを使用し、ベクトルレジスターを最大限に活用し、サイズが大きい場合は、プリフェッチ命令を使用して巧妙な方法で最後のビットを取得しますスピードの。
gnasher729 2015

命令が少ないからといって、実行が速くなるわけではありません。実際、ループの展開、関数のインライン展開、ループの整列により、最適化によってバイナリサイズと命令数が増加することがよくあります...適切な最適化コードを見ると、多くの場合、
不適切な

2

好きなようにしてください。:-)

#ifndef bzero
#define bzero(d,n) memset((d),0,(n))
#endif

ご了承ください:

  1. オリジナルbzeroは何も返さず、memsetvoidポインタ(d)を返します。これは、定義のvoidに型キャストを追加することで修正できます。
  2. #ifndef bzero元の関数が存在していても、それを非表示にすることはできます。マクロの存在をテストします。これは多くの混乱を引き起こす可能性があります。
  3. マクロへの関数ポインタを作成することは不可能です。bzero関数ポインタを介して使用する場合、これは機能しません。

1
@Leeor、これの何が問題なの?マクロに対する一般的な反感?または、このマクロが関数と混同される可能性がある(そしておそらくそれを隠すことさえある)ことを嫌いますか?
Palec、2015

1
@Palec、後者。再定義をマクロとして非表示にすると、混乱が生じる可能性があります。このコードを使用している別のプログラマーは、1つを使用していると考え、無意識のうちにもう1つを使用することを余儀なくされています。それは時限爆弾です。
Leeor、2015

1
もう一度考えてみたところ、これは確かに悪い解決策であることに同意します。とりわけ、技術的な理由を発見しましたbzero。関数ポインタを介して使用する場合、これは機能しません。
Palec 2015

あなたは本当にあなたのマクロを以外のものと呼ぶべきでしたbzero。これは残虐行為です。
Dan Bechard、

-2

memsetは3つのパラメーターを取り、bzeroはメモリー内で2つを取り、追加のパラメーターはさらに4バイトを取り、ほとんどの場合すべてを0に設定するために使用されます。

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