Cのsizeof単一の構造体メンバー


109

別の構造体に依存する構造体を宣言しようとしています。sizeof安全・徹底的に使いたい。

typedef struct _parent
{
  float calc ;
  char text[255] ;
  int used ;
} parent_t ;

次にchild_t、と同じサイズの構造体を宣言したいと思いparent_t.textます。

これどうやってするの?(以下の疑似コード。)

typedef struct _child
{
  char flag ;
  char text[sizeof(parent_t.text)] ;
  int used ;
} child_t ;

parent_tおよびstruct _parentでいくつかの異なる方法を試しましたが、私のコンパイラは受け入れません。

トリックとして、これはうまくいくようです:

parent_t* dummy ;
typedef struct _child
{
  char flag ;
  char text[sizeof(dummy->text)] ;
  int used ;
} child_t ;

child_t使用せずに宣言することは可能ですdummyか?

回答:


202

バッファサイズをaで定義するの#defineは慣用的な方法の1つですが、次のようなマクロを使用する方法もあります。

#define member_size(type, member) sizeof(((type *)0)->member)

次のように使用します。

typedef struct
{
    float calc;
    char text[255];
    int used;
} Parent;

typedef struct
{
    char flag;
    char text[member_size(Parent, text)];
    int used;
} Child;

sizeof((type *)0)->member)定数式としても許可されているので、実際には少し驚いています。クール。


2
うわー、私はsizeof((type *)0)-> member)の動作を知りませんでした。現在私の開発マシンにはありませんが、これはすべてのコンパイラで機能しますか?そのジョーイをありがとう。
ガンガダール2010

4
@Gangadhar:はい、これはすべてのコンパイラで機能します。のオペランドsizeofは評価されないため、nullポインターの逆参照に問題はありません(実際には逆参照されないため)。
James McNellis、2010

4
素晴らしい?その平野C89の実装を参照してください「offsetofは」<STDDEF.H>または同じ実装でeetimes.com/design/other/4024941/...
user411313

1
@XavierGeoffrey:ここで、sizeofは((type *)0)-> memberのタイプを推測し、そのタイプのサイズを返します。((type *)0)は、構造体型の単なるnullポインタです。ptr-> memberは、(コンパイル時に)タイプがメンバーのタイプである式です。sizeof内のコードは実行されません(実行された場合、プログラムはsegfaultになります!)。sizeof内の値のタイプのみが表示されます。
ジョーイアダムス

1
offset_ofWikipediaページでは、これがC標準に従って未定義の動作であると記載されているため、すべてのコンパイラーで動作することには期待していません。
Graeme

30

今は開発マシンにいませんが、次のいずれかを実行できます。

sizeof(((parent_t *)0)->text)

sizeof(((parent_t){0}).text)


編集:私は、このテクニックを使用してJoeyが提案したmember_sizeマクロが好きです。


12
2番目の形式は非常に優れています(また、nullポインターを含まないという点で概念的にはクリーンです)が、C99より前のコンパイラーでは不可能であることを言及する必要があります。
R .. GitHub ICE HELPING ICEの停止

11

FIELD_SIZEOF(t, f)Linuxカーネルで自由に使用できます。次のように定義されています。

#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))

このタイプのマクロは他の回答で言及されています。ただし、すでに定義されているマクロを使用する方が移植性が高くなります。


4
FIELD_SIZEOFは、linux / kernel.hにある最新のLinuxカーネルで使用されているマクロです
Colin Ian King

@ColinIanKingこれは、構造体メンバーのサイズを取得するための一般的なCの慣用的な方法ですか?そのようなマクロは、現代のCの標準にまだ含まれていませんか?
St.Antario 2018

私の知る限りでは、標準のC.には同等のマクロがありません
コリン・イアン・キング

最近、linux / kernel.hから削除されました。
Andriy Makukha

10

プリプロセッサディレクティブ、つまり#defineを使用します。

#define TEXT_LEN 255

typedef struct _parent
{
  float calc ;
  char text[TEXT_LEN] ;
  int used ;
} parent_t ;

typedef struct _child
{
  char flag ;
  char text[TEXT_LEN] ;
  int used ;
} child_t ;

ニャンに同意する。他のソリューションは機能しますが、何も異なることはありません。より明確にしたい場合は、PARENT_TEXT_LENまたは同様に説明的な名前にしてください。その後、コード全体の条件文で使用して、バッファー長のエラーを防止し、単純な整数比較を行うこともできます。
デイブマンコフ2010

1
sizeofソリューションの利点は、ライブラリまたは他の場所で定義されている場合、親構造体にアクセスする必要がないことです。

@evilclown:しかし、あなたはそうします: "char text [member_size(Parent、text)];" 「親」を参照する必要があります。
デイブマンコフ2010

3
あなたは私を理解していないと思います。親構造体がdrand48_data(stdlib.hで定義されている)であり、sizeofが必要だとします__x#define X_LEN 3stdlib.hを変更することはできません。member_size親構造体のソースにアクセスできない場合は、合理的な状況のように使用する方が優れています。

5

次のように、サイズのプリプロセッサディレクティブを使用できます。

#define TEXT_MAX_SIZE 255

親と子の両方で使用します。


うん、しかしそれは常にオプションではありません:たとえば、Linux /usr/include/bits/dirent.hではd_nameフィールド(struct direct/ dirent)のサイズはDIRSIZもはや定義されていませんが、ハードコーディングされています。そのsizeof()依存関係を維持するための唯一のきれいな方法のようだ
ジョージ

5

struct.h それらはすでに定義されています、

#define fldsiz(name, field) \
    (sizeof(((struct name *)0)->field))

そうすることができます、

#include <stdlib.h> /* EXIT_SUCCESS */
#include <stdio.h>  /* printf */
#include <struct.h> /* fldsiz */

struct Penguin {
    char name[128];
    struct Penguin *child[16];
};
static const int name_size  = fldsiz(Penguin, name) / sizeof(char);
static const int child_size = fldsiz(Penguin, child) / sizeof(struct Penguin *);

int main(void) {
    printf("Penguin.name is %d chars and Penguin.child is %d Penguin *.\n",
           name_size, child_size);
    return EXIT_SUCCESS;
}

しかし、ヘッダーを見ると、これはBSDのものであり、ANSIまたはPOSIX標準ではないようです。Linuxマシンで試してみましたが、うまくいきませんでした。限られた有用性。


4

別の可能性は、型を定義することです。2つのフィールドのサイズを同じにしたいという事実は、2つのフィールドのセマンティクスが同じであることを示しています。

typedef char description[255];

そして、フィールドがあります

description text;

あなたの両方のタイプで。


4

c ++ソリューション:

sizeof(Type :: member)も機能しているようです:

struct Parent
{
    float calc;
    char text[255];
    int used;
};

struct Child
{
    char flag;
    char text[sizeof(Parent::text)];
    int used;
};

3
問題は、C ++ではなくCに関するものです。
マルク

0

@ joey-adams、ありがとう!私は同じことを検索していましたが、char以外の配列の場合、この方法でも完全に正常に機能します。

#define member_dim(type, member) sizeof(((type*)0)->member) / \
                                 sizeof(((type*)0)->member[0])

struct parent {
        int array[20];
};

struct child {
        int array[member_dim(struct parent, array)];
};

int main ( void ) {
        return member_dim(struct child, array);
}

期待どおり20を返します。

そして、@ brandon-horsley、これもうまくいきます:

#define member_dim(type, member) sizeof(((type){0}).member) / \
                                 sizeof(((type){0}).member[0])
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.