9

私が次のような構造を持っていると仮定します:

typedef struct
{
    char * string1;
    char * string2;
} TWO_WORDS;

すべてのフィールドが同じタイプであり、私のメインは

TWO_WORDS tw;

string1をtw[0]で参照し、string2をtwo [1]で参照できますか?もしそうなら:

  • これはc標準の一部ですか?
  • 最初に構造体を配列にキャストする必要がありますか?
  • メモリ内のサイズが異なるフィールドはどうですか
  • タイプは異なるが同じサイズのフィールドはどうですか?
  • 構造内でポインタ演算を実行できますか?
  • -
4

7 に答える 7

6

私はこの構造にかなり近づきました:

((char**)&tw)[0];

例として:

int main()
{
    typedef struct
    {
        char * string1;
        char * string2;
    } TWO_WORDS;

    TWO_WORDS tw = {"Hello", "World"};

    printf("String1: %s\n", ((char**)&tw)[0]);
    printf("String2: %s\n", ((char**)&tw)[1]);

    return 0;
}

コンパイラがフィールド間にパディングを追加する可能性があるため、動作は保証されません。(多くのコンパイラには、#pragma構造体のパディングを回避する があります)

それぞれの質問に答えるには:

  • これはc標準の一部ですか?いいえ

  • 最初に構造体を配列にキャストする必要がありますか? はい

  • メモリ内のサイズが異なるフィールドはどうですか
    これは、さらに「邪悪な」キャストとポインター演算で行うことができます

  • タイプは異なるが同じサイズのフィールドはどうですか?
    これは、さらに「邪悪な」キャスティングとポインター演算を使用して実行できます。

  • 構造内でポインタ演算を実行できますか?
    はい (常に期待どおりに動作するとは限りませんが、構造体はポインターとポインター演算でアクセスできる単なるメモリの一部です)

于 2012-06-05T21:56:20.290 に答える
6

@ouahが指摘しているように、そのようにすることはできません。ただし、次のことができます。

typedef union
{ char *a[2];
  struct
  { char *string1;
    char *string2;
  } s;
} TWO_WORDS;

TWO_WORDS t;

t.a[0] = ...;
t.a[1] = ...;
t.s.string1 = ...;
t.s.string2 = ...;
于 2012-06-05T21:57:11.760 に答える
5

いいえ、エミュレートするための特定の手順を実行しない限り、インデックス アクセスを使用してデータ メンバーを構造化することはできません。

C++ では、"pointer-to-data-member" と呼ばれる C++ 固有のポインター型を使用して、この機能をエミュレートできます。C 言語にはそのような型はありませんが、標準のoffsetofマクロとポインター演算を使用してエミュレートできます。

あなたの例では、次のようになります。まず、特別なオフセット配列を用意します

const size_t TW_OFFSETS[] = 
  { offsetof(TWO_WORDS, string1), offsetof(TWO_WORDS, string2) };

このオフセット配列は、後で構造体メンバーへのインデックス アクセスを整理するために使用されます。

*(char **)((char *) &tw + TW_OFFSETS[i]); 
/* Provides lvalue access to either `tw.string1` or `tw.string2` depending on 
   the value of `i` */

見栄えはよくありませんが (マクロを使用して見栄えを良くすることはできます)、C ではそうです。

たとえば、次のように定義できます。

 #define TW_MEMBER(T, t, i) *(T *)((char *) &(t) + TW_OFFSETS[i])

コードで次のように使用します

 TW_MEMBER(char *, tw, 0) = "Hello";
 TW_MEMBER(char *, tw, 1) = "World";

 for (int i = 0; i < 2; ++i)
   printf("%s\n", TW_MEMBER(char *, tw, i));

このアプローチには、構造体をchar*[2]配列として再解釈することに基づくソリューションに存在する重大な問題がないことに注意してください (ユニオンまたはキャストのどちらを介して行われるかに関係なく)。後者はハッキングであり、正式な観点からは違法であり、一般的に無効です。offsetofベースのソリューションは完全に有効で合法です。

于 2012-06-05T22:12:50.140 に答える
3

string1 を tw[0] で参照し、string2 を two[1] で参照できますか?

いいえ、C ではできませんtw。ポインターではなく構造体です。

演算子の制約では[]、オペランドの 1 つをポインター型にする必要があります。

にアクセスするstring1には、次の式を使用できます。tw.string1

于 2012-06-05T21:51:00.433 に答える
1

あなたが((char **)&tw)[0]本当にしたいのであれば、あなたはそれをするために使うことができますが、そうではありませんtw[0].

于 2012-06-05T21:54:22.140 に答える
1

いいえ、C ではそれを行うことはできません。C では、名前を介してのみ構造体メンバーにアクセスできます。

できることは、構造体と同じ文字列へのポインターを持つ配列を作成し、配列のインデックスを使用することです。

しかし、なぜそれをしたいのですか?これで実際に解決しようとしている問題は何ですか?

于 2012-06-05T21:52:15.167 に答える
0

structすべて同じ型のフィールドで始まる がある場合union、その型の構造体と適切なフィールド型の配列を含む を宣言できます。これを行うと、配列の要素を読み書きすると、適切な構造体メンバーが読み書きされます。この動作は、私が知っているすべての実装で機能し、すべてのフィールドが同じサイズであれば移植可能だと思います。

struct quad_int {int n0; int n1; int n2; int n3;}
union quad_int_union {構造体ペア p; int n[4];}

ユニオン quad_int_union my_thing;

my_thing.n[0] は my_thing.p.n0 と同義です
my_thing.n[1] は my_thing.p.n1 と同義です
等

于 2012-06-06T07:09:23.353 に答える