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

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

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

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

Q&A

解決済

5回答

4258閲覧

【C】printfの引数の挙動について

masaya_math

総合スコア16

C

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

0グッド

1クリップ

投稿2021/08/27 12:32

編集2021/08/27 13:10

###問題のコード

C

1#include <stdlib.h> 2#include <stdio.h> 3 4int main(void) 5{ 6 double A[5] = { 7 [0] = 9.0, 8 [1] = 2.9, 9 [4] = 3.e+25, 10 [3] = .00007, 11 }; 12 13 for (size_t i = 0; i < 5; ++i) 14 { 15 if (i) 16 { 17 printf("element %zu is %g, \tits square is %g\n", 18 i, 19 A[i], 20 A[i] * A[i]); 21 } 22 } 23 24 return EXIT_SUCCESS; 25}

###当該のコードについて発生した警告
too many arguments for format [-Wformat-extra-args]
###解決したいこと
####一
警告が発生する原因を理解したい。明らかに引数の個数は正しいと思われるにもかかわらずこのような警告が出される理由がわからないため。
####ニ
もしコードに問題があれば、警告を受けない正しい書き方に訂正したい。
###補足
iまたはA[i]またはA[i]*A[i]のどれか一つを引数から削除すれば警告は現れなくなる。
環境はWindowsで、mingw-w64のgccを用いたvscodeのデバッガを用いている。コンパイラも実行もできるが、警告が出ている状態(おそらく-Wallフラグを立てているため)。
警告は他に2つほど出ていて、それぞれ
unknown conversion type character 'z' in format [-Wformat=]
format '%g' expects argument of type 'double', but argument 2 has type 'size_t' {aka 'long long unsigned int'} [-Wformat=]
となっています。
iはsize_t、Aはdouble[]型で宣言されています。
更に追記:WSLのgccで全く同じコードを同じgccのコマンドでコンパイルしてみたところ警告は何も出ませんでした。一方でwindowsのmingw-w64ではやはり3つの警告が出ました。
更に追記:-std=99オプションを付与した場合も同様の警告文でした。また、gccのバージョンは8.1.0です。

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

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

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

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

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

itagagaki

2021/08/27 12:43

質問にgccのバージョンを付記してください。 それとgccに -std=c99 オプションを付けてコンパイルしてみた結果も教えてください。
masaya_math

2021/08/27 13:05

追記させていただきました。
SaitoAtsushi

2021/08/27 13:07

関係なさそうな部分は除外してもよいですが、コンパイル可能な (しかし同等のエラーや警告が再現する) 最小限のコードとして提示するのが好ましいです。 「Aはdouble[]型で宣言されています」などの前提条件の部分でなんらかの間違いがある可能性もあるのでそのあたりの行き違いを失くす意味や、単純にコピー&ペーストできると検証が楽だからです。
masaya_math

2021/08/27 13:11

ありがとうございます。修正させていただきました。
guest

回答5

0

警告のメッセージからすると z を理解していないということがわかります。 C の言語仕様はたびたび更新されており、 z が書式 (長さ修飾子) に現れることができるようになったのは 1999 年の改定 (通称 C99) からで、それ以前には存在しませんでした。

そして Windows 側の事情なのですが、 MinGW でコンパイルした場合には printf は Windows 内にある msvcrt.dll 内の printf を使おうとする場合があります。 msvcrt.dll のバージョンによっては z を認識しないため gcc の側では z は使えないものとして処理しているようです。

コンパイル時の指定などで解決できるはずですが、私の手元に再現できる環境を用意してないので詳細は説明できないです。 ちなみに MSYS2 のパッケージマネージャ経由で MinGW (10.3.0) を導入した場合にはこの問題は起こらないようです。 (私の手元ではそうしてます。)

投稿2021/08/27 13:22

SaitoAtsushi

総合スコア5675

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

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

0

unknown conversion type character 'z' in formatのとおりで、%zは認識しない環境があります。

投稿2021/08/27 12:45

maisumakun

総合スコア145930

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

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

0

maisumakun さんの回答の通りなのですが、MinGWgccはデフォルトではMSVCのライブラリ (msvcrt.dll) を使用します。
最新のMSVCのライブラリは"%zu"を受け付けますが、msvcrt.dllはサポートしていない可能性もあります。(警告を無視して実行すると正確な値を表示するので、もしかしたらサポートしたのかもしれませんが、あるいは単に "z" を無視しているのかも)

ソースファイルの先頭 (#include <stdio.h>の前) に

C

1#define __USE_MINGW_ANSI_STDIO 1

を追加すると、自前のライブラリを使用するので、警告も出ないですし結果も正常です。
あるいは、コンパイルオプションに-D __USE_MINGW_ANSI_STDIO=1を指定しても同様です。

投稿2021/08/27 13:49

Bull

総合スコア986

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

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

Bull

2021/08/27 13:53

あらら、解決してしまいましたか。 でも "-D __USE_MINGW_ANSI_STDIO=1" は結構有効なので、私はいつも指定しています。
guest

0

MinGWはマイクロソフトのCライブラリmsvcrtを使用しているが、このライブラリはC89にしか準拠しておらず、%zを理解しない、という情報がありました。%zが導入されたのはC99です。

https://stackoverflow.com/questions/44382862/how-to-printf-a-size-t-without-warning-in-mingw-w64-gcc-7-1#comment75766032_44382862

投稿2021/08/27 13:21

編集2021/08/27 13:22
itagagaki

総合スコア8402

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

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

0

自己解決

皆様のご回答をもとに更に調べた結果、原因の理解と解決策を得られました。
まず、too many argument警告の原因は、maisumakun様のご指摘の通り%zuを私の環境下では認識していなかったことでした。
では、私の環境下でも認識できるsize_t用の指定子はなんだろう、と思い調べた結果、どうやら32ビット環境であれば%lu(long unsigned)指定子で表せるようですが、私の環境は64bit環境であり、size_tが表しているものもlong long unsignedです。そして、どうやら(言うなれば%lluのような)64bit環境でのsize_tを直接表せるz以外の指定子は存在していない模様です。
そこで考えられる解決策は、size_tをlong unsignedにキャストして、%lu指定子でフォーマットすることです。実際にこれを試してみた結果、すべての警告が消えました。
上記の解決策は、本来の型を半分のbitサイズの型にキャストする方法であるため、そこは注意が必要です。
以上で問題は完全に解決されました。ご協力くださった皆様、誠にありがとうございました。

投稿2021/08/27 13:29

masaya_math

総合スコア16

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

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

itagagaki

2021/08/27 13:36

SaitoAtsushiさんが導入したMinGWの版では問題ないようですので、MinGW環境の更新を検討されるのがベストではないかと私は思います。
rubato6809

2021/08/27 22:22

> size_t用の指定子はなんだろう その出発点がずれていませんか。for (size_t i = 0; の i は配列の添え字です。それなら int でよかったのでは? int なら "%d" で済んだ話だと思いました。
rubato6809

2021/08/29 13:03 編集

気になって調べたら × https://teratail.com/questions/356503https://teratail.com/questions/278714 でも int でよかったという事例だと私は思います。 ・メモリ空間の半分どころか、たった[0]~[4] しかアクセスしないならintで十分だった ・%zu を使ったが故に互換性の罠にひっかかった。 教条主義・原理主義はほどほどに、が私のアドバイスです。 とはいえ、%zuの互換性という問題に気づけたのは良かったです。
rubato6809

2021/08/29 13:04

恥ずかしい事に、違うリンクを貼っていたことに先ほど気づいた orz 誰かツッコんでよ(苦笑
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.37%

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

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

質問する

関連した質問