これは、要素の種類によって部分的に異なります。確かに文字列でそれを行うことができます。他のいくつかのタイプでは、配置とパディングの問題について心配する必要があります。
struct data_channel
{
char *chan_name;
char *chan_type;
char *chan_units;
};
struct data_channel *chan;
size_t name_size = 9;
size_t type_size = 10;
size_t unit_size = 5;
chan = malloc(sizeof(struct data_channel) + name_size + type_size + unit_size);
if (chan != 0)
{
chan->chan_name = (char *)chan + sizeof(*chan);
chan->chan_type = chan->chan_name + name_size;
chan->chan_units = chan->chan_type + type_size;
}
これは実際には問題なく動作します — 標準が標準化される前から長い間行われていました。標準がこれを禁止する理由がすぐにはわかりません。
int
さらに厄介なのは、2 つの文字列だけでなく、たとえばの配列を割り当てる必要がある場合です。次に、アライメントの問題について心配する必要があります。
struct data_info
{
char *info_name;
int *info_freq;
char *info_unit;
};
size_t name_size = 9;
size_t freq_size = 10;
size_t unit_size = 5;
size_t nbytes = sizeof(struct data_info) + name_size + freq_size * sizeof(int) + unit_size;
struct data_info *info = malloc(nbytes);
if (info != 0)
{
info->info_freq = (int *)((char *)info + sizeof(*info));
info->info_name = (char *)info->info_freq + freq_size * sizeof(int);
info->info_unit = info->info_name + name_size;
}
int
これは、最も厳密に整列された型 ( の配列) を最初に割り当て、次に文字列を後で割り当てるという単純な方法を採用しています。ただし、この部分では、移植性について判断を下す必要があります。コードは実際に移植可能であると確信しています。
C11には、この回答を変更できるアライメント機能(_Alignof
and _Alignas
and <stdalign.h>
、plus max_align_t
in <stddef.h>
)があります(ただし、十分に調査していないため、方法はまだわかりません)が、ここで概説されている手法は、Cのどのバージョンでも機能します。データの配置には注意してください。
構造体に単一の配列がある場合、C99 はフレキシブル配列メンバー(FAM)と呼ばれる古い「構造体ハック」の代替手段を提供することに注意してください。これにより、配列を構造体の最後の要素として明示的に持つことができます。
struct data_info
{
char *info_name;
char *info_units;
int info_freq[];
};
size_t name_size = 9;
size_t freq_size = 10;
size_t unit_size = 5;
size_t nbytes = sizeof(struct data_info) + name_size + freq_size * sizeof(int) + unit_size;
struct data_info *info = malloc(nbytes);
if (info != 0)
{
info->info_name = ((char *)info + sizeof(*info) + freq_size * sizeof(int));
info->info_units = info->info_name + name_size;
}
info_freq
この例では、FAM を初期化する手順がないことに注意してください。このように複数の配列を持つことはできません。
概要を説明した手法は、構造体の配列 (少なくとも外部構造体の配列) には簡単に適用できないことに注意してください。かなりの努力をすれば、それを機能させることができます。また、注意してくださいrealloc()
。スペースを再割り当てする場合、データが移動した場合はポインターを修正する必要があります。
もう 1 つのポイント: 特に 64 ビット マシンでは、文字列のサイズが十分に均一である場合は、ポインターを使用する代わりに、構造体に配列を割り当てる方がよいでしょう。
struct data_channel
{
char chan_name[16];
char chan_type[16];
char chan_units[8];
};
これは 40 バイトを占有します。64 ビット マシンでは、元のデータ構造は 3 つのポインター用に 24 バイトを占有し、(9 + 10 + 5) バイトのデータ用に別の 24 バイトを占有し、合計 48 バイトが割り当てられます。