2

私は C とその難解な隠された力についてもっと学ぼうとしており、配列として使用することを意図した、void へのポインターを含むサンプル構造体を作成しようとしました。編集: 重要な注意: これは生の C コード用です。

この構造体があるとしましょう。

    typedef struct mystruct {
        unsigned char foo;
        unsigned int max;
        enum data_t type;
        void* data;

    } mystruct;

データにunsigned char、unsigned short int、unsigned long int のいずれかの最大値を保持させたい場合、data_t 列挙にはこれら 3 つのケースの値が含まれます。

    enum Grid_t {gi8, gi16, gi32}; //For 8, 16 and 32 bit uints.

次に、この構造体の 1 つを初期化して割り当てるこの関数があり、新しい構造体へのポインターを返すことになっています。

    mystruct* new(unsigned char foo, unsigned int bar, long value) {
        mystruct* new;
        new = malloc(sizeof(mystruct)); //Allocate space for the struct.
        assert(new != NULL);
        new->foo = foo;
        new->max = bar;
        int i;
        switch(type){
            case gi8: default:
                new->data = (unsigned char *)calloc(new->max, sizeof(unsigned char));
                assert(new->data != NULL);
                for(i = 0; i < new->max; i++){
                    *((unsigned char*)new->data + i) = (unsigned char)value;
                    //Can I do anything with the format new->data[n]? I can't seem
                    //to use the [] shortcut to point to members in this case!
                }
            break;
        }
        return new;
    }

コンパイラは警告を返しませんが、この方法についてはよくわかりません。ポインターを使用する正当な方法ですか?

より良い方法©はありますか?

呼び損ねました。mystruct* P; のように P = 新しい (0,50,1024);

ユニオンは興味深いですが、私が望んでいたものではありません。とにかく、特定のケースごとに個別にアプローチする必要があるため、キャストはユニオンと同じくらい良いようです。特に、32 ビット配列よりもはるかに大きな 8 ビット配列が必要だったので、共用体は役に立たないようです。そのために、私はそれを単にlongの配列にします:P

4

4 に答える 4

2

void*いいえ、ポインタを逆参照することはできません。C言語標準では禁止されています。そうする前に、それを具象ポインタ型にキャストする必要があります。

別の方法として、ニーズに応じて、構造体で:unionの代わりにを使用することもできます。void*

typedef struct mystruct {
    unsigned char foo;
    unsigned int max;
    enum data_t type;
    union {
        unsigned char *uc;
        unsigned short *us;
        unsigned int *ui;
    } data;
} mystruct;

data.uc常に、、、data.usまたはのいずれか1つだけdata.uiが有効です。これらはすべて、メモリ内の同じスペースを占有するためです。次に、適切なメンバーを使用して、からキャストしなくてもデータ配列を取得できますvoid*

于 2011-08-04T19:26:25.933 に答える
1

どうですか

typedef struct mystruct 
{
    unsigned char foo;
    unsigned int max;
    enum data_t type;
    union
    {
        unsigned char *chars;
        unsigned short *shortints;
        unsigned long *longints; 
    };
} mystruct;

そうすれば、キャストする必要はまったくありません。data_tアクセスするポインタを決定するために使用するだけです。

于 2011-08-04T19:24:36.053 に答える
0

ポインタは、メモリ空間内の単なるアドレスです。あなたはそれをあなたが望むように解釈することを選ぶことができます。union同じメモリ位置を複数の方法で解釈する方法の詳細については、を確認してください。

ポインター型間のキャストはCとC++で一般的であり、void *の使用は、ユーザーが誤って逆参照しないようにすることを意味します(void *を逆参照するとエラーが発生しますが、int *にキャストするときに同じポインターを逆参照しません)

于 2011-08-04T19:26:10.300 に答える
0

type関数への引数であるはずですか? (この関数に名前を付けたり、変数に名前を付けたりしないでください。これnewを使用しようとする C++ プログラマーはあなたを追い詰めます)

配列インデックスを使用する場合は、次のような一時ポインターを使用できます。

unsigned char *cdata = (unsigned char *)new->data;
cdata[i] = value;

あなたのアプローチに問題はありません。特定のサイズが予想される場合(名前などを考えるとそうすると思います) 、 typedef 、、およびをgi8含めて使用することをお勧めします。stdint.huint8_tuint16_tuint32_t

于 2011-08-04T19:23:07.113 に答える