質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

18336閲覧

memsetでの初期化(64bit)

long_long_time

総合スコア11

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

1グッド

1クリップ

投稿2016/06/07 07:55

初めまして・・・

今まで32bit版上で動作していたプログラムを64bit環境で
gccコマンドにてコンパイルを行ったら
以下の「警告」が出力されました。
「警告: キャストによってポインタから異なるサイズの整数となります」
複数箇所で「警告」が出力されていますが、すべて以下の様なソースでした。

memset((void*)strLineBuf, (int)NULL, sizeof(strLineBuf));

この「警告」が問題あるのかないのか判らないので以下のように
変更してコンパイルしてみたら問題なくコンパイルされました。
memset((void*)strLineBuf, (long)NULL, sizeof(strLineBuf));

ここで質問です。
1.「警告」は無視しても問題ない。
2.longに変更するのが正しい。
3.ともに間違いである。正しくは・・・・・

どれが正しいのでしょうか?

環境は、Red Hat Enterprise Linux Server release 6.8 です。

退会済みユーザー👍を押しています

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

単純に0埋めをしたいのであれば、他の皆さんが示すとおり、NULLではなく単純に0または'\0'を使うべきです。ですが、それ以外でも問題があるコードになっていますので、そこについて述べさせていただきます。(つまり、ただの蛇足です)

###ほとんどの環境においてNULL((void *)0)であり、整数値の0と同じとは限りません。
C言語では0というリテラルがポインタとして解釈されるときはヌルポインタとすると定義されています。ヌルポインタは値が0のポインタという意味では無く、どこもさしていないことが保証されたポインタという意味です。そして、マクロ定数NULLが先ほどのヌルポインタになるようにマクロを定義するとしています。そのため、gccではNULL((void *)0)としています(あくまでgccの場合であり、他のコンパイラも同じであるという保証はありません)。

注意すべきはヌルポインタはリテラルが0なだけで、実際のデータが全て0であるとは限らないと言うことです。(int)NULLつまり(int)((void *)0)が、(int)0と同じになる保証はありません。

そして、今回は、memsetがバイト単位で書き込むと言うことがもっと意味不明なコードにしてしまっています。もし、NULLのメモリ上の実際のデータが[0x12 0x34 0x56 0x78]なら、リトルエンディアンの環境では[0x12 0x12 0x12 0x12]と書き込まれていくことになります。これはきっと、期待している動作では決して無いでしょう。

つまり、ヌルポインタで埋めたいという状況であっても、memsetの第2引数にNULLを使うこと自体が間違っています

※ NULLの読み方にはナル派(英語かぶれ)とヌル派(独語かぶれ)の二つの派閥があります。
NULLとは違い'\0'は実際のメモリ上のデータが0であることを表しています。

参考:
[迷信] とりあえず memset で初期化 | 株式会社きじねこ
C言語の基礎知識(?)メモ(Hishidama's C Memo)#NULL

###void *型をキャストするときはintptr_tまたはuintptr_tを使うべきです。
void *のサイズがlongで収まるという保証はありません(事実、Windowsのx86_64環境では収まりません)。intで足りないから安直にlongとしてはいけません。ポインタのサイズが必ず収まるという整数型としてintptr_tuintptr_tが用意されています。ポインタを整数として扱いたい場合は、こちらを使うべきです。

intptr_t等が使えないC90で書く必要がある場合は、プリプロセッサで分岐するなどの工夫をする必要があります。

投稿2016/06/07 10:17

raccy

総合スコア21733

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

catsforepaw

2016/06/07 11:51

C++ではNULLは`0`なので完全に0の代わりにできますね。0の代わりにNULLと書いているコードをたまに見かけます。そのコードを真似してC言語で書いたことでご質問のような問題になったのではないかと推察しています。 あと、intptr_tが使えない場合はsize_tで代用できそうな気がします。
raccy

2016/06/07 21:41 編集

> catsforepawさん 今時のC++ならnullptrを使わないと!!! 0の代わりにNULLと書いている人は、きっと他の言語でも0の代わりにnullやnilと書いたりしそうで怖いですね。は!これは0とnullの違いがうまく新人に伝わらないって質問に通じる話題だったのか!!! size_tは配列インデックスなどの限界値であってアドレスの範囲をすべて含むわけではないようです。 http://stackoverflow.com/questions/1464174/size-t-vs-intptr-t
long_long_time

2016/06/07 23:08

丁寧な回答・解説ありがとうございます。回答を参考にしていきたいと思います。
catsforepaw

2016/06/08 05:24

raccy さん > 今時のC++ならnullptrを使わないと!!! もちろん私はそうしていますよ。 > は!これは0とnullの違いがうまく新人に伝わらないって質問に通じる話題だったのか!!! そ、そうなのですよ、それが言いたかったのですよ……。 > size_tは配列インデックスなどの限界値であってアドレスの範囲をすべて含むわけではないようです。 確かに言われてみればそうですね。16bit時代は物理アドレスは20bit(24bit)だけどポインタは16bitなんてこともありましたね。
guest

0

こんにちは。

NULLがポインタとして定義されている場合、64bit環境では64bitのサイズを持つことになります。
そして、int型は32bitの場合が多いです。
ですので、64bitサイズのポインタ値を32bit整数へキャストするというありがちなミスを警告しているだと思います。

0クリアするのであれば、memset((void*)strLineBuf, 0, sizeof(strLineBuf));と書いた方が素直なので意味も分かりやすいように思います。

投稿2016/06/07 08:30

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

long_long_time

2016/06/07 23:02

ありがとうございます。0でクリアすれば良いのですね。
guest

0

ゼロクリアならキャストする必要がないと思います。

lang

1memset((void *)strLineBuf, 0, sizeof(strLineBuf));

文字列なら 0 ではなく明示的に '\0' で初期化することもあるようです。

投稿2016/06/07 08:28

chitoku

総合スコア1610

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

memsetはバイト単位でメモリを初期化するのでどちらでも動作は同じになるはずです。
警告が出るのは、整数型のサイズが32bitと64bitで違うためです。キャストをlongにして警告がなくなったということはLinux系のOSでしょうか?WindowsとLinuxではlongのサイズが違うみたいですね。

C99/C++11では環境非依存の方が準備されてます。(int32_t/uint32_tなど)
こういう型を使うことで移植性を上げることはできると思います。

コンパイラ警告は無視しても良い場合が多いのですが、中にはまずいものもあります。なので、私は警告もなるべく出ないようにソースを書いています。

投稿2016/06/07 08:39

PineMatsu

総合スコア3579

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

long_long_time

2016/06/07 23:06

ありがとうございます。int32_t/uint32_t は知りませんでした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問