本当に簡単
すべてのビットが設定された符号なし定数を作成するにはどうすればよいですか?
...フィールドを { } で初期化するために使用できます。
...これは、GCC 4.7.2 から -Wnarrowing 警告を受けません。
以下は満足のいくものではありません。
struct U { unsigned ufield; };
struct Uc { unsigned char ufield; };
struct ULL { unsigned long long ufield; };
struct U32 { unsigned ufield; };
struct U64 { uint64_t ufield; }
typedef
//any of the above U Uc ULL U32 U64, we will arbitrarily choose:
U Ueg;
// somewhere far away
Ueg u = {-1}; // well defined by C standard, GCC 4.7.2 -Wnarrowing warning
Ueg u = {~0U}; // finit width constant, warnings in some places, silent non-all-1s-mask others
Ueg u = {~0ULL}; // ditto
Ueg u = {-1ULL}; // ditto
基本的に、{} 初期化を書いているユーザーは、ufield の型を知りません。彼はそれが unsigned 型であることだけを知っていますが、幅は知りません。それがどの符号なしタイプであるかは正確ではありません。
* できるだけシンプルでエレガントな構文が必要なもう 1 つの理由 *
ここでの「ユーザー」は、実際に C または C++ プログラムを書いているわけではありません。彼は構成ファイルを編集しています。プログラム (単純な Perl または Python スクリプト) が構成ファイルを処理し、C コードを生成します。このプログラムはあまり洗練されたものではなく、現時点では次のようなテキストのチャンクを通過します。
Foo: {-1,2,3};
typedef struct Some_Struct { unsigned a; を生成します。符号なし b、符号なし c; } Some_Struct = {-1,2,3}; //同上
基本的に、「この符号なし値のすべてのビットが設定されている」というリテラルのユーザーフレンドリーな構文を作成できるようにしたいと考えています。署名されていないものがどれほど大きいかを知る必要はありません。また、構成ファイルを処理するプログラムが複雑になりすぎることもありません。
潜在的な回答プロバイダーが、これは新しい制約であり、現実的ではないなどと文句を言わないように
します。テンプレートに関してまったく同じ問題がありました。つまり、「任意の幅の符号なし、すべて 1」のリテラルを書きたいテンプレート型の場合です。テンプレートでは、明らかにこれを行うことができる醜い、醜い、醜い構文のいくつかを実行したいと思うかもしれません: しかし、シンプルでエレガントな構文があればいいのにと思います。
*本当の質問*
Q: GCC 4.7.2 警告をトリガーせずに「すべて 1 が設定されている」定数を作成する方法はありますか?
簡単に
リテラル定数 -1 を使用して構造体のフィールドを初期化するプログラムに出くわしました。
> cat ./-1u.cpp
#include <stdio.h>
struct U { unsigned ufield; } ustruct = { -1 };
int main(int argc, char** argv)
{
printf("ustruct.ufield = %08x\n",ustruct.ufield);
}
以前のバージョンの GCC では警告なしでこれを受け入れていましたが、かなり最近のバージョンの GCC 4.7.2 では警告が表示されます。
> /SOME-PATH/import/gcc/gcc-4.7.2.pkg/installdir/bin/g++ -Wall ./-1u.cpp
./-1u.cpp:3:46: warning: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
注: これは単なる警告です。-1 を unsigned に変換した結果は、C/C++ 標準で明確に定義されています。
> ./a.out
ustruct.ufield = ffffffff
私は警告が嫌いなので、この迷惑な警告を黙らせたいと思います。ファイル全体に適用される #pragmas は使用しないほうがよいと思います。実際のバグに対する警告が無効になる可能性があるためです。
(ちなみに、この警告は、フィールドを初期化するときのみ表示されます。フィールド以外を初期化するときは表示されません。
unsigned u = -1; // no cmpiler warning.
やっている
struct U { unsigned ufield; } ustruct = { ~0U };
バグを沈黙させます。
しかし、フィールドの型が unsigned ではなく uint64_t である場合、~0U は -1 とは異なる結果を提供することが指摘されました: 0xFFFFFFFFFFFFFFFF ではなく 0x00000000FFFFFFFF。(つまり、64 ビットの 1 ではなく、32 ビットの 1 です。)
構造体 U と初期化コードは完全に異なる場所に存在する可能性があり、ユーザーに通知せずにフィールドのサイズ、ビットマスクを増やすことができるようにしたいと考えています。その意図は、使用されている符号なしタイプの「すべて 1 のマスク」を取得することです。
同様に
struct U { unsigned ufield; } ustruct = { -1u };
バグを沈黙させます。(驚いたことに、-1 が unsigned と見なされる可能性があることを知りませんでした。)
しかし、有限幅の定数でもあります。
詳細
ここにテストプログラムがあります。(ちなみに、私が尋ねているのは、署名されていないメンバーを初期化するために符号付きリテラル定数 -1 を使用することだけです。他の警告は単なるテストです。64 ビットの数値がそうでないことを説明する必要はありません。 32 ビットに収まります。)
sh-3.2$ cat ./-1u.cpp
#include <stdio.h>
unsigned um1 = -1;
unsigned un0u = ~0u;
unsigned un0ull = ~0ull;
struct Foo {
unsigned um1;
unsigned un0u;
unsigned un0ull;
};
Foo foo = { -1, ~0u, ~0ull };
int main(int argc, char** argv)
{
printf("um1 = %08x\n",um1);
printf("un0u = %08x\n",un0u);
printf("un0ull = %08x\n",un0ull);
printf("foo.um1 = %08x\n",foo.um1);
printf("foo.un0u = %08x\n",foo.un0u);
printf("foo.un0ull = %08x\n",foo.un0ull);
}
sh-3.2$ /mips/proj/performance/import/gcc/gcc-4.7.2.pkg/installdir/bin/gcc -Wall ./-1u.cpp
./-1u.cpp:7:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
./-1u.cpp:15:28: warning: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:28: warning: narrowing conversion of '18446744073709551615ull' from 'long long unsigned int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:28: warning: large integer implicitly truncated to unsigned type [-Woverflow]
sh-3.2$ /mips/proj/performance/import/gcc/gcc-4.7.2.pkg/installdir/bin/g++ -Wall ./-1u.cpp
./-1u.cpp:7:20: warning: large integer implicitly truncated to unsigned type [-Woverflow]
./-1u.cpp:15:35: warning: narrowing conversion of '-1' from 'int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:35: warning: narrowing conversion of '18446744073709551615ull' from 'long long unsigned int' to 'unsigned int' inside { } is ill-formed in C++11 [-Wnarrowing]
./-1u.cpp:15:35: warning: large integer implicitly truncated to unsigned type [-Woverflow]
以前のコンパイラでは発生しません:
sh-3.2$ /usr/bin/g++ -Wall ./-1u.cpp
./-1u.cpp:7: warning: large integer implicitly truncated to unsigned type
./-1u.cpp:15: warning: large integer implicitly truncated to unsigned type
/usr/bin/g++ --version
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-51)
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.