複合リテラル (C99以降)
From cppreference.com
指定された型 (構造体、共用体、さらには配列型も可) の名前のないオブジェクトをインプレースで構築します。
目次 |
[編集] 構文
( storage-class-specifiers (任意)(C23以降) type ) { initializer-list } |
(C99以降) | ||||||||
( storage-class-specifiers (任意)(C23以降) type ) { initializer-list , } |
(C99以降) | ||||||||
( storage-class-specifiers (任意) type ) { } |
(C23以降) | ||||||||
ここで、
| storage-class-specifiers | - | (C23以降) constexpr、static、register、または thread_local のみを含むことができる 記憶域クラス指定子 のリスト。 |
| type | - | 完全なオブジェクト型またはサイズ不明の配列を指定する 型名。ただし、VLA は不可。 |
| initializer-list (初期化子リスト) | - | type のオブジェクトの 初期化 に適した初期化子リスト。 |
[編集] 説明
複合リテラル式は、type によって指定された型の名前のないオブジェクトを構築し、initializer-list によって指定されたとおりに初期化します。指定初期化子 が受け入れられます。
複合リテラルの型は type です (ただし、type がサイズ不明の配列である場合を除く。そのサイズは、配列の初期化 と同様に、initializer-list から推測されます)。
複合リテラルの値カテゴリは lvalue です (そのアドレスを取得できます)。
| 複合リテラルがファイルスコープで発生する場合、複合リテラルが評価される名前のないオブジェクトは静的 記憶域期間 を持ち、複合リテラルがブロックスコープで発生する場合、自動 記憶域期間 を持ちます (この場合、オブジェクトの 生存期間 は囲むブロックの終了時に終了します)。 | (C23まで) |
複合リテラルが関数の本体の外側およびパラメータリストの外側で評価される場合、それはファイルスコープに関連付けられます。それ以外の場合は、囲むブロックに関連付けられます。この関連付けに応じて、記憶域クラス指定子 (空の場合もあります)、型名、および初期化子リスト (存在する場合) は、次の形式のファイルスコープまたはブロックスコープでのオブジェクト定義の有効な指定子となるように、それらである必要があります。 storage-class-specifiers typeof(type) ID = { initializer-list };
ここで、ID はプログラム全体で一意の識別子です。複合リテラルは、その値、型、記憶域期間、およびその他のプロパティが上記の定義構文で与えられるかのように、名前のないオブジェクトを提供します。記憶域期間が自動の場合、名前のないオブジェクトのインスタンスの生存期間は、囲むブロックの現在の実行です。記憶域クラス指定子に constexpr、static、register、または thread_local 以外の指定子が含まれている場合、動作は未定義です。 |
(C23以降) |
[編集] 注意
const 修飾された文字またはワイド文字配列型の複合リテラルは、文字列リテラル と記憶域を共有する場合があります。
(const char []){"abc"} == "abc" // might be 1 or 0, unspecified
各複合リテラルはそのスコープで 1 つのオブジェクトのみを作成します。
int f (void) { struct s {int i;} *p = 0, *q; int j = 0; again: q = p, p = &((struct s){ j++ }); if (j < 2) goto again; // note; if a loop were used, it would end scope here, // which would terminate the lifetime of the compound literal // leaving p as a dangling pointer return p == q && q->i == 1; // always returns 1 }
複合リテラルは名前がないため、複合リテラルはそれ自体を参照できません (名前付き構造体はそれ自体へのポインタを含むことができます)。
複合リテラルの構文は キャスト に似ていますが、重要な違いは、キャストは非 lvalue 式であるのに対し、複合リテラルは lvalue であることです。
[編集] 例
このコードを実行
#include <stdio.h> int *p = (int[]){2, 4}; // creates an unnamed static array of type int[2] // initializes the array to the values {2, 4} // creates pointer p to point at the first element of // the array const float *pc = (const float []){1e0, 1e1, 1e2}; // read-only compound literal struct point {double x,y;}; int main(void) { int n = 2, *p = &n; p = (int [2]){*p}; // creates an unnamed automatic array of type int[2] // initializes the first element to the value formerly // held in *p // initializes the second element to zero // stores the address of the first element in p void drawline1(struct point from, struct point to); void drawline2(struct point *from, struct point *to); drawline1( (struct point){.x=1, .y=1}, // creates two structs with block scope and (struct point){.x=3, .y=4}); // calls drawline1, passing them by value drawline2( &(struct point){.x=1, .y=1}, // creates two structs with block scope and &(struct point){.x=3, .y=4}); // calls drawline2, passing their addresses } void drawline1(struct point from, struct point to) { printf("drawline1: `from` @ %p {%.2f, %.2f}, `to` @ %p {%.2f, %.2f}\n", (void*)&from, from.x, from.y, (void*)&to, to.x, to.y); } void drawline2(struct point *from, struct point *to) { printf("drawline2: `from` @ %p {%.2f, %.2f}, `to` @ %p {%.2f, %.2f}\n", (void*)from, from->x, from->y, (void*)to, to->x, to->y); }
実行結果の例
drawline1: `from` @ 0x7ffd24facea0 {1.00, 1.00}, `to` @ 0x7ffd24face90 {3.00, 4.00}
drawline2: `from` @ 0x7ffd24facec0 {1.00, 1.00}, `to` @ 0x7ffd24faced0 {3.00, 4.00}[編集] 参照
- C23標準 (ISO/IEC 9899:2024)
- 6.5.2.5 複合リテラル (p: TBD)
- C17標準 (ISO/IEC 9899:2018)
- 6.5.2.5 複合リテラル (p: 61-63)
- C11標準 (ISO/IEC 9899:2011)
- 6.5.2.5 複合リテラル (p: 85-87)
- C99標準 (ISO/IEC 9899:1999)
- 6.5.2.5 複合リテラル (p: 75-77)