C++の__builtin_offsetof
演算子 ( Symbian では演算子)の目的は何ですか?_FOFF
さらに、それは何を返しますか?ポインタ?バイト数?
offsetof
これは、C および C++ 標準で指定されているマクロを実装するために、GCC コンパイラによって提供される組み込みです。
POD 構造体/共用体のメンバーのオフセットをバイト単位で返します。
サンプル:
struct abc1 { int a, b, c; };
union abc2 { int a, b, c; };
struct abc3 { abc3() { } int a, b, c; }; // non-POD
union abc4 { abc4() { } int a, b, c; }; // non-POD
assert(offsetof(abc1, a) == 0); // always, because there's no padding before a.
assert(offsetof(abc1, b) == 4); // here, on my system
assert(offsetof(abc2, a) == offsetof(abc2, b)); // (members overlap)
assert(offsetof(abc3, c) == 8); // undefined behavior. GCC outputs warnings
assert(offsetof(abc4, a) == 0); // undefined behavior. GCC outputs warnings
@Jonathan は、それを使用できる場所の良い例を提供します。侵入型リスト (データ項目に next および prev ポインター自体が含まれるリスト) を実装するために使用されたのを見たのを覚えていますが、悲しいことに、それを実装するのにどこが役に立ったか思い出せません。
@litb が指摘し、@JesperE が示すように、offsetof() はバイト単位の整数オフセットを (size_t
値として) 提供します。
いつ使用できますか?
関連する可能性がある 1 つのケースは、ファイルから膨大な数の多様な構成パラメーターを読み取り、その値を同じように巨大なデータ構造に詰め込むためのテーブル駆動型操作です。非常に些細なことに減らします (そして、ヘッダーで構造型を定義するなど、さまざまな必要な現実世界の慣行を無視します)、いくつかのパラメーターは整数であり、他のパラメーターは文字列である可能性があり、コードはかすかに次のように見える可能性があることを意味します。
#include <stddef.h>
typedef stuct config_info config_info;
struct config_info
{
int parameter1;
int parameter2;
int parameter3;
char *string1;
char *string2;
char *string3;
int parameter4;
} main_configuration;
typedef struct config_desc config_desc;
static const struct config_desc
{
char *name;
enum paramtype { PT_INT, PT_STR } type;
size_t offset;
int min_val;
int max_val;
int max_len;
} desc_configuration[] =
{
{ "GIZMOTRON_RATING", PT_INT, offsetof(config_info, parameter1), 0, 100, 0 },
{ "NECROSIS_FACTOR", PT_INT, offsetof(config_info, parameter2), -20, +20, 0 },
{ "GILLYWEED_LEAVES", PT_INT, offsetof(config_info, parameter3), 1, 3, 0 },
{ "INFLATION_FACTOR", PT_INT, offsetof(config_info, parameter4), 1000, 10000, 0 },
{ "EXTRA_CONFIG", PT_STR, offsetof(config_info, string1), 0, 0, 64 },
{ "USER_NAME", PT_STR, offsetof(config_info, string2), 0, 0, 16 },
{ "GIZMOTRON_LABEL", PT_STR, offsetof(config_info, string3), 0, 0, 32 },
};
構成ファイルから行を読み取り、コメントと空白行を破棄する一般的な関数を作成できるようになりました。次に、パラメーター名を分離し、それをdesc_configuration
テーブルで検索します (バイナリ検索を実行できるように並べ替えることができます - 複数の SO 質問がそれに対処します)。正しいconfig_desc
レコードが見つかると、見つかった値とconfig_desc
エントリを 2 つのルーチンのいずれかに渡すことができます。1 つは文字列の処理用、もう 1 つは整数の処理用です。
これらの機能の重要な部分は次のとおりです。
static int validate_set_int_config(const config_desc *desc, char *value)
{
int *data = (int *)((char *)&main_configuration + desc->offset);
...
*data = atoi(value);
...
}
static int validate_set_str_config(const config_desc *desc, char *value)
{
char **data = (char **)((char *)&main_configuration + desc->offset);
...
*data = strdup(value);
...
}
これにより、構造体の個別のメンバーごとに個別の関数を作成する必要がなくなります。
組み込み演算子の目的は__offsetof
、コンパイラ ベンダーがマクロを #define し続けoffsetof()
ながら、 unary を定義するクラスで動作させることができるようにすることoperator&
です。の典型的な C マクロ定義は、その右辺値のアドレスが返されたoffsetof()
場合にのみ機能しました。(&lvalue)
いえ
#define offsetof(type, member) (int)(&((type *)0)->member) // C definition, not C++
struct CFoo {
struct Evil {
int operator&() { return 42; }
};
Evil foo;
};
ptrdiff_t t = offsetof(CFoo, foo); // Would call Evil::operator& and return 42
@litbが言ったように、構造体/クラスメンバーのバイト単位のオフセット。C++ では、コンパイラが文句を言う場合に備えて、未定義の場合があります。IIRC、それを(少なくともCで)実装する1つの方法は、
#define offsetof(type, member) (int)(&((type *)0)->member)
しかし、これには問題があると確信していますが、それは興味のある読者に指摘してもらいます...