掲示板利用宣言

 次のフォームをすべてチェックしてからご利用ください。

 私は

 題名と投稿者名は具体的に書きます。
 課題の丸投げはしません。
 ソースの添付は「HTML変換ツール」で字下げします。
 返信の引用は最小限にします。
 環境(OSとコンパイラ)や症状は具体的に詳しく書きます。
 返信の付いた投稿は削除しません。
 マルチポスト(多重投稿)はしません。

掲示板2

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧

No.27337

gccの「互換性のないポインタ型」という警告
投稿者---CHAKAFU(2006/06/26 14:31:07)


プログラム(main.c)をgccでコンパイルすると以下の警告が出てしまいます。
「二次元配列の変更を許さない、正しい関数渡しの表記方法」は
どうすれば良いのか教えて下さい。
gccのバージョンは3.2.2です。


gcc main.c -W -Wall

main.c: 関数 `main' 内:
main.c:9: 警告: 互換性のないポインタ型からの引数 1 個の `func' を渡しますです


プログラムはこうなってます。

void  func( const int a[10][10] )
{
}

int  main()
{
    int  a[10][10];

    func( a );

    return 0;
}



よろしくお願いいたします。


この投稿にコメントする

削除パスワード

発言に関する情報 題名 投稿番号 投稿者名 投稿日時
<子記事> Re:gccの「互換性のないポインタ型」という警告 27338 Hermit 2006/06/26 15:53:35


No.27338

Re:gccの「互換性のないポインタ型」という警告
投稿者---Hermit(2006/06/26 15:53:35)


const が付いているために、型が違うと怒られているのではないでしょうか。
func() の const をのけるか、
func( (const int (*)[10])a );
の様にキャストするか、
どちらかではないかとおもいますが。


この投稿にコメントする

削除パスワード

No.27339

gccの「互換性のないポインタ型」という警告
投稿者---CHAKAFU(2006/06/26 16:37:36)


ご返信ありがとうございます。

constが付いているために警告が出るのであれば、
以下のプログラムでも警告が出るはずだと私は思うのです(一次元配列にした)。
しかし実際は警告されませんでした。


void  func( const int a[10] )
{
}


int  main()
{
    int a[10];

    func( a );

    return 0;
}


この投稿にコメントする

削除パスワード

No.27343

Re:gccの「互換性のないポインタ型」という警告
投稿者---Hermit(2006/06/26 18:47:42)


gcc のバグで無いでしょうか。


この投稿にコメントする

削除パスワード

No.27347

Re:gccの「互換性のないポインタ型」という警告
投稿者---yoh2(2006/06/26 21:53:02)


>gcc のバグで無いでしょうか。

文章が愉快な日本語もどきなのはgccのバグですが、警告が出ること自体はバグではないです。……多分。

# ちなみに、あの警告メッセージは、英文では
#「passing arg 1 of `func' from incompatible pointer type」となります。

私なりに規格書(JIS X 3010:2003 以下、X3010)を解釈した結果を説明してみます。微妙な所ですので、間違っている可能性も高いのですが。
どなたかダメ出しなり同意なりしてくれるとうれしいです。

まず、ポインタの代入がOKなのは以下の条件を満たすときです(X3010 6.5.16.2)。

(1) 代入する側とされる側が同じ型の修飾型または非修飾型へのポインタ
(2) 代入される側が、代入する側の修飾子をすべて持つ

さて、これをふまえて、警告が出ない場合
func(const int a[10]) /* func(const int *a)と同義 */
を見てみると、
代入する側: int *
代入される側: const int *
なので、(1)両方とも同じ型(int)へのポインタで、(2)代入する側の修飾子(なし)を、代入される側が全て持っている(代入される側の修飾子:const)ので、代入はOKとなります。

一方、警告が出る場合
func(const int a[10][10]) /* func(const int (*a)[10])と同義 */
は、
代入する側: int (*)[10]
代入される側: const int (*)[10]
なので、代入する側は「int [10]」へのポインタ、代入される側は、「const int [10]」へのポインタとなります。
一見、OKな場合の「int」が「int [10]」になっただけのように見えますが、これが曲者。
「const int [10]」は、「const付の(int型の10個の配列)」という意味ではなく、「(const付のint型)の10個の配列」という意味になります(X3010 6.7.3)。つまり、int[10]とconst int[10]は全く関係ない型とみなされます。
その結果、const int (*)[10]とint(*)[10]は互換性のない型だと言われるわけです。

ちなみに、C++では、const int (*)[10]は、意味的には「(const付のint型)の10個の配列」ですが、型としては「const付の(int型の10個の配列)」とみなすという規則があり(JIS X 3014:2003 8.3.4; 解釈がかなりあやしいです)、
const int (*)[10]に、int (*)[10]を代入できます。
実際、GCC(g++)でコンパイルすると警告もエラーも出ません。


この投稿にコメントする

削除パスワード

No.27348

Re:gccの「互換性のないポインタ型」という警告
投稿者---Hermit(2006/06/26 22:34:15)


そういう捕らえ方も出来るんですか。
解釈としては、わからないわけでもないですが、

プログラムとしてどう書くと、警告無しで書けるかが問題な気がします。
書けないのであれば、それは gcc のバグか、ANSI 規格のバグになると思いますが。
まあ、仕様という言葉に置き換えることも出来ますが(^^;

でも、元々は、GNU C は、ANSI に正確に沿ってはいなかったから、
(ANSI にある程度従うのと、ANSI に厳密に従うオプションはあったけど)
いまさら ANSI がどうのこうのと言うほどでもないけど。


この投稿にコメントする

削除パスワード

No.27349

Re:gccの「互換性のないポインタ型」という警告
投稿者---Hermit(2006/06/26 22:35:55)


あ、gcc は、JIS でなく、ANSI C 99 に沿っていたと思います。


この投稿にコメントする

削除パスワード

No.27359

gccの「互換性のないポインタ型」という警告
投稿者---CHAKAFU(2006/06/27 11:29:50)


なるほど。難しいですが確かにg++では警告は出ませんでした。
これからはg++でコンパイルしようかな...

私もぜひ知りたいのが、プログラムとしてどう書くと、警告無しで書けるかです。
キャストしないとだめなんでしょうか。


この投稿にコメントする

削除パスワード

No.27361

Re:gccの「互換性のないポインタ型」という警告
投稿者---iijima(2006/06/27 13:23:25)


>なるほど。難しいですが確かにg++では警告は出ませんでした。
>これからはg++でコンパイルしようかな...
>
>私もぜひ知りたいのが、プログラムとしてどう書くと、警告無しで書けるかです。
>キャストしないとだめなんでしょうか。

本件についてなぜ警告が出る/出ないかはよく分かりませんが、一般論としていえば、コンパイラは正しく動作しない可能性があるところを警告しているのですから、そこを見直して言語規格上もロジック上も問題ないことが確認できれば、その警告は無視しても構わないものだと考えます。

型チェックの関係ではキャストによってコンパイラを黙らせられる場合もありますが、警告を出さないことを目的にキャストするクセをつけてしまうと、本当に不正な場所も見逃してしまうことになり、却ってデバグを難しいものにします。

警告を消すことだけを目的にコンパイラを変えたりキャストしたりすることは、私はしません。


この投稿にコメントする

削除パスワード

No.27366

Re:gccの「互換性のないポインタ型」という警告
投稿者---Hermit(2006/06/27 19:42:21)


>本件についてなぜ警告が出る/出ないかはよく分かりませんが、一般論としていえば、コンパイラは正しく動作しない可能性があるところを警告しているのですから、そこを見直して言語規格上もロジック上も問題ないことが確認できれば、その警告は無視しても構わないものだと考えます。

そのコンパイラのベテランの上級者ならそれでかまわないのですが、
初心者や初級者程度だと、問題があるかどうかがわからないので
非常につらい所だと思います。


この投稿にコメントする

削除パスワード

No.27396

Re:gccの「互換性のないポインタ型」という警告
投稿者---iijima(2006/06/28 10:50:06)


>>本件についてなぜ警告が出る/出ないかはよく分かりませんが、
>>一般論としていえば、コンパイラは正しく動作しない可能性があるとこ
>>ろを警告しているのですから、そこを見直して言語規格上もロジック上
>>も問題ないことが確認できれば、その警告は無視しても構わないものだ
>>と考えます。

>そのコンパイラのベテランの上級者ならそれでかまわないのですが、
>初心者や初級者程度だと、問題があるかどうかがわからないので
>非常につらい所だと思います。

そうですね。確かに難しいところですね。

ただ、初心者であっても、警告が出た場所に本当に問題があるかどうかを
調べて理解しようとする努力を惜しんではいけないと思います。

その努力を惜しみ、ワケは分からないが警告が消えるから、という理由だ
けでキャストするようなことだけはしてほしくないです。

>私もぜひ知りたいのが、プログラムとしてどう書くと、警告無しで書けるかです。
>キャストしないとだめなんでしょうか。

これに、ややそういう「気配」が感じられたので、老婆心ながら申し上げ
た次第です。あくまで一般論としてです。


この投稿にコメントする

削除パスワード

No.27408

Re:gccの「互換性のないポインタ型」という警告
投稿者---yoh2(2006/06/28 21:57:06)


>>>本件についてなぜ警告が出る/出ないかはよく分かりませんが、
>>>一般論としていえば、コンパイラは正しく動作しない可能性があるとこ
>>>ろを警告しているのですから、そこを見直して言語規格上もロジック上
>>>も問題ないことが確認できれば、その警告は無視しても構わないものだ
>>>と考えます。

私は、警告が出た場合、(1)それが問題ないものであると判断したら、
そして、それが、(2)警告が出ない、他の綺麗なコードに書き直すことが
できないと判断したら、多少不恰好でも、強引にキャストするなり
なんなりして警告が出ないようにする口です。
大量の問題のない警告に埋もれて、肝心の致命的な警告を見落とすのが嫌ですので。
とはいえ、経験則では、多くの場合、うまく書き直すことができるので(2)の条件に
引っかかります。
でもこのツリーで話題になっているコードはキャストしないとダメかなぁ。
プロトタイプ変更もよろしくなさげですし。

ただ、これは、問題ない警告は消さずに無視するという方法を否定する
ものではありません。
強引に警告を消す癖が付くことと、重要な警告を見落とすことのどちらを
より問題視するか、というだけの話です。

# 警告を放置する理由には、警告を出す基準はコンパイラによって違うのだから、
# 特定のコンパイラが出す警告をわざわざ消すのは謎コードを増やすだけ、
# というものもあるかな。

警告を無理矢理消すにしろ、放置するにしろ、一番重要なのは

>ただ、初心者であっても、警告が出た場所に本当に問題があるかどうかを
>調べて理解しようとする努力を惜しんではいけないと思います。

に尽きますね。
エラーが起きたら嫌でも問題点を理解しないと先に進めませんが、
警告程度のものでもその本質を理解するように努めることで
ベテランに近づけると思います。

そんな偉そうなことを書いている私もひよっこですけどね。


この投稿にコメントする

削除パスワード

No.27407

Re:gccの「互換性のないポインタ型」という警告
投稿者---yoh2(2006/06/28 21:16:03)


以下の部分、間違っていました。すみません。

>ちなみに、C++では、const int (*)[10]は、意味的には「(const付のint型)の10個の配列」ですが、

× const int (*)[10]は、
○ const int [10]は、


この投稿にコメントする

削除パスワード

管理者用メニュー    ツリーに戻る    携帯用URL    ホームページ    ログ    タグ一覧