パディング/アライメントの問題を無視するで、次の構造体が与えられた場合、メンバー名を使用せずにmember_bの値を取得および設定するための最良の方法は何ですか。
struct mystruct {
int member_a;
int member_b;
}
struct mystruct *s = malloc(sizeof(struct mystruct));
別の言い方をすると、ポインター/オフセットの観点から、次のことをどのように表現しますか?
s->member_b = 3;
printf("%i",s->member_b);
私の推測は
int
)のサイズを見つけてオフセットを計算しますchar
?)にキャストしますint
ポインターを作成し、アドレスを(*charpointer + offset
?に)設定しますint
ポインタを使用してメモリの内容を設定するしかし、char型へのキャストについて少し混乱したり、memset
のようなものがより適切である場合や、一般的にこれを完全に間違っている場合は、.
助けてくれて乾杯
概説したアプローチはおおよそ正しいですが、自分でオフセットを計算する代わりにoffsetof
を使用する必要があります。なぜあなたがmemset
について言及しているのかはわかりません-ブロックの内容を指定された値に設定します。
これがどのように機能するかを示すためのコードです:
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct x {
int member_a;
int member_b;
} x;
int main() {
x *s = malloc(sizeof(x));
char *base;
size_t offset;
int *b;
// initialize both members to known values
s->member_a = 1;
s->member_b = 2;
// get base address
base = (char *)s;
// and the offset to member_b
offset = offsetof(x, member_b);
// Compute address of member_b
b = (int *)(base+offset);
// write to member_b via our pointer
*b = 10;
// print out via name, to show it was changed to new value.
printf("%d\n", s->member_b);
return 0;
}
完全なテクニック:
Offsetofを使用してオフセットを取得します。
b_offset = offsetof(struct mystruct、member_b);
構造体のアドレスをchar *ポインターとして取得します。
char * sc =(char *)s;
オフセットを構造体アドレスに追加し、値を適切なタイプへのポインタにキャストして逆参照します。
*(int *)(sc + b_offset)
あなたが言ったように、パディングと配置を無視します...
例のように、ポイントしている要素が完全に単一の型である場合は、構造体を目的の型にキャストして配列として扱うことができます。
printf("%i", ((int *)(&s))[1]);
構造体と参照ポインタとしてのNULLに基づいてオフセットを計算できます。例: "&(((type *)0)-> field)"
例:
struct my_struct {
int x;
int y;
int *m;
int *h;
};
int main()
{
printf("offset %d\n", (int) &((((struct my_struct*)0)->h)));
return 0;
}
この特定の例では、*((int *) ((char *) s + sizeof(int)))
でアドレス指定できます。なぜあなたがそれを望んでいるのかわからないので、私は教訓的な目的を想定しているので、説明は次のとおりです。
コードのビットは次のように変換されます。アドレスsから始まるメモリを取得し、char
を指すメモリとして扱います。そのアドレスにsizeof(int)
char
- chunksを追加します-新しいアドレスを取得します。このようにして作成されたアドレスの値を取り、int
として扱います。
*(s + sizeof(int))
を書き込むと、s
にアドレスを加え、sizeof(int)
sizeof(mystruct)チャンクが得られることに注意してください。
編集:アンドレイのコメントに従って offsetof を使用:
*((int *) ((byte *) s + offsetof(struct mystruct, member_b)))
編集2:sizeof(char)
が1であることが保証されているため、すべてのbyte
sをchar
sに置き換えました。
コメントから、実際に行っているのは、さまざまなデータ型の束を単一のメモリブロックにパックおよびアンパックすることです。他のほとんどの答えが示唆しているように、あなたはcan直接ポインタキャストでそれをやめることを避けます:
void set_int(void *block, size_t offset, int val)
{
char *p = block;
*(int *)(p + offset) = val;
}
int get_int(void *block, size_t offset)
{
char *p = block;
return *(int *)(p + offset);
}
問題は、これが移植不可能であることです。タイプが正しい配置でブロック内に格納されるようにする一般的な方法はありません。一部のアーキテクチャでは、配置されていないアドレスに対してロードまたは格納を実行できません。ブロックのレイアウトが宣言された構造によって定義される特殊なケースでは、構造体のレイアウトに正しい配置を確保するために必要なパディングが含まれるため、問題ありません。ただし、名前でメンバーにアクセスすることはできないため、実際にはそうではないようです。
これを移植可能にするには、memcpy
を使用する必要があります。
void set_int(void *block, size_t offset, int val)
{
char *p = block;
memcpy(p + offset, &val, sizeof val);
}
int get_int(void *block, size_t offset)
{
char *p = block;
int val;
memcpy(&val, p + offset, sizeof val);
return val;
}
(他のタイプも同様)。