命名空间
变体
操作

复合字面量 (自 C99 起)

来自 cppreference.com
< c‎ | 语言

在指定位置构建指定类型(可以是结构体、联合体,甚至是数组类型)的无名对象。

内容

[编辑] 语法

( 存储类说明符 (可选)(自 C23 起) 类型 ) { 初始化列表 } (自 C99 起)
( 存储类说明符 (可选)(自 C23 起) 类型 ) { 初始化列表 , } (自 C99 起)
( 存储类说明符 (可选) 类型 ) { } (自 C23 起)

其中

存储类说明符 - (自 C23 起) 一系列 存储类说明符,只能包含 constexprstaticregisterthread_local
类型 - 一个 类型名称,指定任何完整对象类型或大小未知的数组,但不能是 VLA
初始化列表 - 用于 初始化 类型 对象的初始化器列表

[编辑] 解释

复合字面量表达式构建一个指定类型为 类型 的无名对象,并按 初始化列表 指定的方式进行初始化。 指定初始化器 被接受。

复合字面量的类型为 类型(除非 类型 是大小未知的数组;其大小从 初始化列表 中推断出来,如同 数组初始化 一样)。

复合字面量的值类别为 左值(可以获取其地址)。

复合字面量求值到的无名对象具有静态 存储期,如果复合字面量出现在文件作用域,或具有自动 存储期,如果复合字面量出现在块作用域(在这种情况下,对象的 生命周期 在封闭块结束时结束)。 (直到 C23)
如果复合字面量在函数体外部和任何参数列表外部求值,则它与文件作用域相关联;否则,它与封闭块相关联。根据这种关联,存储类说明符(可能为空)、类型名称和初始化列表(如果有)必须是有效的说明符,用于以下形式的文件作用域或块作用域的
   storage-class-specifiers typeof(type) ID = { initializer-list };
其中 ID 是整个程序唯一的标识符。复合字面量提供一个无名对象,其值、类型、存储期和其他属性如同上面定义语法给出的那样;如果存储期是自动的,则无名对象的实例的生命周期是封闭块的当前执行。如果存储类说明符包含除 constexprstaticregisterthread_local 之外的其他说明符,则行为未定义。
(自 C23 起)

[编辑] 备注

const 限定的字符或宽字符数组类型的复合字面量可能与 字符串字面量 共享存储。

(const char []){"abc"} == "abc" // might be 1 or 0, unspecified

每个复合字面量在其作用域中只创建一个对象。

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
}

因为复合字面量是无名的,所以复合字面量不能引用自身(命名结构体可以包含指向自身的指针)。

虽然复合字面量的语法类似于 强制转换,但重要的是,强制转换是非左值表达式,而复合字面量是左值。

[编辑] 示例

#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)