C语言中是否出现过(int [2]){19,20}
或int (*pt2)[4]
的使用方法可能不容易理解,这是C99之后新增的一个特性,称为”复合字面量(Compound Literals)”。一旦熟悉使用,就会发现它的简洁和强大。
什么是复合字面量?
假设要向带有int类型形参的函数传递一个值,可以传递int类型的变量,也可以传递int类型的常量。但是对于带有数组形参的函数来说,情况就不同了。可以传递数组,但不支持传递数组常量。为了解决这个问题,C99引入了复合字面量的概念。这里的字面量是指除了符号常量以外的常量。
例如,10是int类型的字面量,10.24是double类型的字面量,”lixiaoyao”是字符串的字面量等。如果涉及到数组或结构体的字面量,使用复合字面量会更加方便。
数组的复合字面量
数组的复合字面量与数组初始化列表类似。使用括号括起来的类型名来声明,下面是一个普通的数组声明的例子。
int age[2]=[19,20];
下面创建了一个和age数组相同的匿名数组,也有两个int类型值
(int [2]){19,20}; //复合字面量
注意去掉申明中的数组名,留下的int[2]
就是复合字面量的类型名。
初始化有数组名的数组可以省略数组的大小,复合字面量也可以省略大小,编译器会自动计算数组当前的元素个数:
(int []){19,20,21,22,23}//内含5个元素的复合字面量
因为复合字面量是匿名的,所以不能先创建然后再使用它,必须在创建的同时使用它,如下
int x;
// 正确
x = 100;
int arr[1];
// 错误
arr = {0};
一般需要这样定义使用:
int *pt1;
pt1=(int[2]){19,20};
注意,该复合字面量的字面常量与上面创建age数组的字面常量完全相同,复合字面的类型名也代表着首元素的地址,所以可以把它赋给指向int的指针。
作为实际参数
复合字面量作为实际参数传递给带有匹配形式参数的函数
#include
int sum(const int age[],int n);
int main () {
int total;
total =sum((int[]){4,4,4,5,5,5},6);
return 0;
}
int sum(const int age[],int n){
int i=0;
for(i=0;iprintf("age is %d\n",age[i]);
}
}
输出结果如下:
应用于二维数组或者多维数组
这种用法还可以应用于二维或者多维数组,例如下面演示了如何创建二维int数组并存储其地址
int (*pt2)[4];
//申明一个指向二维数组的指针,该数组内有2个数组元素
//每个元素是内含4个int类型值的数组
pt2 = (int [2][4]) {{1,2,3,4,},{5,6,7,8,}};
对于结构体
假设如下所示声明了struct foo和structure:
struct foo {
int a;
char b[2];
} structure;
这是使用复合字面量构造struct foo的示例:
structure = ((struct foo) {x + y, 'a', 0});
这等效于以下代码:
{
struct foo temp = {x + y, 'a', 0};
structure = temp;
}
也可以构造一个数组,如下所述,如果复合字面量的所有元素都是由简单的常量表达式组成,则可以将复合字面量强制转换为指向其第一个元素的指针,并在此类初始化程序中使用, 如下所示:
char **foo = (char *[]) { "x", "y", "z" };
标量类型和联合类型的复合字面量也被允许,在下面的示例中,变量i初始化为值2,该值是由复合字面量创建的未命名对象递增的结果。
int i = ++(int){1};
作为GNU扩展,GCC允许通过复合字面量初始化具有静态存储持续时间的对象,如果复合字面量和对象的类型匹配,则如同仅使用括号括起来的列表初始化对象一样处理该对象,复合字面量的元素必须是常量。如果要初始化的对象具有未知大小的数组类型,则该大小由复合字面量的大小确定。
static struct foo x = (struct foo) {1, 'a', 'b'};
static int y[] = (int []) {1, 2, 3};
static int z[] = (int [3]) {1};
等效于以下内容:
static struct foo x = {1, 'a', 'b'};
static int y[] = {1, 2, 3};
static int z[] = {1, 0, 0};
C/C++中的区别
复合字面量看起来像是用括号括起来的聚合初始化程序列表的强制转换,它的值是强制类型转换中指定类型的对象,其中包含初始化程序中指定的元素。
与强制转换的结果不同,复合字面量是左值,但是 C++ 中目前还没有这种无名左值,作为扩展,GCC在C90模式和C++中也支持复合字面量,但C++语义有所不同。
在C中,复合字面量表示具有静态或自动存储持续时间的未命名对象;在C++中,复合字面量表示一个临时对象,该对象仅在其完整表达式结束之前一直存在。
所以,定义良好的C代码(采用复合字面量的子对象的地址)可以在C++中未定义,因此g++编译器不能将临时数组转换为指针。
例如,如果上面的数组复合字面量示例出现在函数内部,则C++中对foo的任何后续使用都将具有未定义的行为,因为数组的生存期在声明foo之后结束。
作为一种优化,g++编译器有时会给数组复合字面量提供更长的生存期:当数组出现在函数外部或具有const限定类型时。如果foo及其初始化程序的元素类型为char * const
而不是char *
,或者foo为全局变量,则该数组将具有静态存储持续时间。
以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !