私はこれをC++/g ++で行うことができます:
struct vec3 {
union {
struct {
float x, y, z;
};
float xyz[3];
};
};
その後、
vec3 v;
assert(&v.xyz[0] == &v.x);
assert(&v.xyz[1] == &v.y);
assert(&v.xyz[2] == &v.z);
働くでしょう。
Gccを使用してcでこれを行うにはどうすればよいですか?私が持っています
typedef struct {
union {
struct {
float x, y, z;
};
float xyz[3];
};
} Vector3;
しかし、特にエラーが発生します
line 5: warning: declaration does not declare anything
line 7: warning: declaration does not declare anything
http://gcc.gnu.org/onlinedocs/gcc/Unnamed-Fields.html#Unnamed-Fields
-fms-extensions
は、あなた(そして私)が望む機能を有効にします。
(この回答はC11ではなくC99に適用されます)。
C99には匿名の構造体や共用体はありません。それらに名前を付ける必要があります:
typedef struct {
union {
struct {
float x, y, z;
} individual;
float xyz[3];
} data;
} Vector3;
そして、それらにアクセスするときに名前を使用する必要があります。
assert(&v.data.xyz[0] == &v.data.individual.x);
この場合、最上位レベルの構造にはユニオン型の単一のアイテムがあるため、これを単純化できます。
typedef union {
struct {
float x, y, z;
} individual;
float xyz[3];
} Vector3;
データへのアクセスは次のようになります。
assert(&v.xyz[0] == &v.individual.x);
新しいC11規格は、匿名の構造と組合をサポートします。2011年4月のドラフトの序文パラグラフ6を参照してください。
http://en.wikipedia.org/wiki/C1X
奇妙な部分は、gccとclangの両方が、C89およびC99モードで匿名の構造とユニオンをサポートするようになったことです。私のマシンでは警告は表示されません。
また、いつでも次のことができます。
typedef struct
{
float xyz[0];
float x, y, z;
}Vec3;
長さゼロの配列はストレージを割り当てず、Cに「次に宣言されるものを指すように」だけを伝えます。次に、他の配列と同じようにアクセスできます。
int main(int argc, char** argv)
{
Vec3 tVec;
for(int i = 0; i < 3; ++i)
{
tVec.xyz[i] = (float)i;
}
printf("vec.x == %f\n", tVec.x);
printf("vec.y == %f\n", tVec.y);
printf("vec.z == %f\n", tVec.z);
return 0;
}
結果:
vec.x == 0.000000
vec.y == 1.000000
vec.z == 2.000000
過剰な妄想になりたい場合は、プラットフォームに合わせてデータパッキング戦略を手動で指定できます。
匿名結合はC++言語の機能です。 C言語には匿名の結合はありません。
匿名の構造体は、CにもC++にも存在しません。
質問で提示した宣言はGCC C++コンパイラでコンパイルできますが、コンパイラ固有の拡張であり、標準Cと標準C++のどちらとも関係ありません。
その上、どのように実装するかに関係なく、C言語もC++言語もアサーションが保持されることを保証しません。
警告なしでGCCでこれを行うことができます
typedef union {
struct { // human-friendly access
float x;
float y;
float z;
float w;
};
float xyz[3];
struct { // human-friendly access
float r;
float g;
float b;
float a;
};
float rgb[3];
} Vector4f;
int main()
{
Vector4f position, normal, color;
// human-friendly access
position.x = 12.3f;
position.y = 2.f;
position.z = 3.f;
position.w = 1.f;
normal.x = .8f;
normal.y = .9f;
normal.z = .1f;
normal.w = 1.f;
color.r = 1.f;
color.g = .233f;
color.b = 2.11f;
color.a = 1.1f;
// computer friendly access
//some_processor_specific_operation(position.vec,normal.vec);
return 0;
}
C:\> gcc vec.c-壁
C:\> gcc --version gcc(GCC)4.4.0 Copyright(C)2009 Free Software Foundation、Inc.これはフリーソフトウェアです。コピー条件のソースを参照してください。保証はありません。市場性や特定の目的への適合性でさえも。
Cでは、匿名結合はサポートされていません。
また、次のように宣言する場合にも注意してください。
typedef struct {
union {
struct {
float x, y, z;
} individual;
float xyz[3];
} data;
} Vector3;
やること
Vector3 v;
v.data.xyz[0] = 5;
float foo = v.data.individual.x;
未定義の動作です。最後に割り当てられた組合員にのみアクセスできます。あなたの場合、標準で指定されていない多くのことに依存しているため、ユニオンの使用は間違っており、コーディング慣行が悪いです(パディング...)。
Cでは、次のようなものを好むでしょう。
typedef struct {
float v[3];
} Vec3;
また、v [x]を使用したくない場合は、以下を検討できます。
#define X(V) ((V).v[0])
Vec3 v;
X(v) = 5.3;
printf("%f\n", X(v));
ANSI/ISO C99標準ではない正体不明の構造体メンバーがこれを説明しますが、おもしろいことが起こることがわかります。GNU Cコンパイラ2.xxバージョンのポートでは、それらは、「xはunion\struct yのメンバーではありません、xとは何ですか?」などとは言いません。他の場合は、「xは未定義」、「xはstructのメンバーではありません」、これが原因で、「未知へのポインタ」を見たことがあると誓います。
したがって、私は専門的にこれについて全員と一緒に行き、struct\unionメンバーに識別子を与えるか、UNIONの場合は慎重にコードを再配置して、組合が特定された構造の特定されたメンバーと元の組合の未特定の構造に埋め込まれ、特定された構造のメンバーになり、特定された組合メンバーと慎重に使用されます。しかし、後者の方法が有効な代替手段ではない場合、これらのケースでは、私は単に厄介な構造に識別子を与えて先に進みます。
CのGNU方言は、匿名の構造体/共用体をサポートしますが、デフォルトでは、GCCは何らかの標準Cを使用してコンパイルします。GNU方言を使用するには、コマンドラインでstd = gnu99 ".