web-dev-qa-db-ja.com

GCCでフォーマット切り捨ての警告を回避するにはどうすればよいですか?

次のgcc format-truncation警告が表示されます。

test.c:8:33: warning: ‘/input’ directive output may be truncated writing 6 bytes into a region of size between 1 and 20 [-Wformat-truncation=]
snprintf(dst, sizeof(dst), "%s-more", src);
                             ^~~~~~
test.c:8:3: note: ‘snprintf’ output between 7 and 26 bytes into a destination of size 20
snprintf(dst, sizeof(dst), "%s-more", src);
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

このようなコードでは:

char dst[20];
char src[20];
scanf("%s", src);
snprintf(dst, sizeof(dst), "%s-more", src);
printf("%s\n", dst);

私はそれが切り捨てられるかもしれないことを知っています-しかし、これがまさにそもそもsnprintfを使用している理由です。これが意図されていることをコンパイラに明らかにする方法はありますか(プラグマまたは-Wno-format-truncationを使用せずに)?

10
Marius Melzer
  1. 警告はgcc7.1に侵入しました。 gcc7.1リリースの変更 を参照.
  2. gcc docs から:

-Wformat-truncation [...]のレベル1は、戻り値が使用されておらず、出力が切り捨てられる可能性が最も高い境界関数の呼び出しについてのみ警告します。

  1. 問題は バグレポート であり、NOTABUGとしてクローズされました。

通常、未処理の出力の切り捨てはプログラムのバグです。 [...]
切り捨てが予想される場合、呼び出し元は通常、関数からの戻り値をチェックし、何らかの方法で処理します(たとえば、分岐することにより)。これらの場合、警告は発行されません。警告によって出力されるソース行は、これがこれらのケースの1つではないことを示唆しています。警告は、意図されたとおりに実行しています。

  1. ただし、エラー時に負の値を返すsnprintfの戻り値を確認するだけです。
_#include <stdio.h>
#include <stdlib.h>
void f(void) {
    char dst[2], src[2];
    // snprintf(dst, sizeof(dst), "%s!", src);

    int ret = snprintf(dst, sizeof(dst), "%s!", src);
    if (ret < 0) {
         abort();
    }

    // But don't we love confusing one liners?
    for (int ret = snprintf(dst, sizeof(dst), "%s!", src); ret < 0;) exit(ret);
    // Can we do better?
    snprintf(dst, sizeof(dst), "%s!", src) < 0 ? abort() : (void)0;
    // Don't we love obfuscation?
#define snprintf_nowarn(...) (snprintf(__VA_ARGS__) < 0 ? abort() : (void)0)
    snprintf_nowarn(dst, sizeof(dst), "%s!", src);
}
_

テスト済み https://godbolt.org/ gcc7.1 gcc7.2 gcc7.3 gcc8.1 with _-O{0,1,2,3} -Wall -Wextra -pedantic_。警告を一切出しません。 gcc8.1は、-O1_よりも大きい最適化でabort()への呼び出しを最適化/削除します。

11
Kamil Cuk

精度指定子を追加できます。これはsrcから最大14文字を出力し、フォーマット文字列の切り捨ての可能性を回避し、その警告をトリガーしません:

snprintf(dst, sizeof(dst), "%.14s-more", src);

オンラインコンパイラ

4
VTT