C语言的小括号和花括号结合使用&&复合语句

先上代码,对于基于f-statck协议栈改进项目时候,看到一段代码,内核里面的很多宏也经常使用这种复合型语句,看了相关的资料和博客,写下来自己的理解:

static int (*real_clock_gettime) (clockid_t , struct timespec *);
#define SYSCALL(func)                                       \
    ({                                                      \
        if (unlikely(!real_##func)) {                       \
            real_##func = dlsym(RTLD_NEXT, #func);          \
        }                                                   \
        real_##func;                                        \
    })
相关调用:   
int clock_gettime_real(clockid_t clk_id,struct timespec *tp)
{        
        return SYSCALL(clock_gettime)(clk_id, tp);
}

第一次看大概明白real_clock_gettime函数未定义(大概率)时,从动态链接库操作句柄与符号,获得函数的地址,并赋给函数指针real_clock_gettime,而在函数clock_gettime_real被调用时候,先进行SYSCALLL的宏替换并调用函数real_clock_gettime(clk_id,tp)返回值等于该函数返回值。但是第一次看还是觉得理解就好并且只是认为默认都这么用,没有关心这背后的道道,怎么最终变成return real_clock_gettime(clk_id,tp);

这边涉及到复合语句的使用,结合<C与指针>,看了一些博客,又重新熟悉了一遍复合语句使用。

复合语句:根据百度词条描述的是,把多个语句用括号{}括起来组成的一个语句称复合语句。

复合语句用的最多的一个地方就是在一些语句中,如选择和循环语句,if,for,while中,本来只能后面跟随一条语句,利用复合语句可以达到多条语句变成一条语句的效果。当然在<C与指针>,用{}也是一个代码块,有代码块作用域,一些变量声明在代码块声明时,也只能在这块区域内才能被访问。

而当复合语句被小括号包裹起来时,能被充当表达式的作用(个人理解),借用别人博客的例子说明:

https://blog.csdn.net/npy_lp/article/details/7015066

#include <stdio.h>
 
int main(void)
{
    int a = ({ int b = 8;
	    int c = 99;
	    b + c;
	    b + c - 10;
	    });
 
    printf("a = %d\n", a);
 
    return 0;
}

这里的执行结果a = 97,因此({ })的作用是一个表达式,表达式的值是最后复合语句的最后一个语句的值,类型是最后一个语句的类型。这边时候已经大概明白({})的作用了,如图:

像(Statements and Declarations in Expressions)这类的复合语句,我更愿意理解为是一个表达式,即小括号加上复合型语句变成一个表达式,整体({})执行的过程为先执行复合语句里面的每个表达式直到最后一个,然后返回一个表达式,而表达式值为小括号内最后一个表达式的值,数据类型也为最后一个表达式的数据类型。

当时为了证明这一个过程,写了一些测试代码

#include <stdio.h>

int main(void)
{
        char *p;
        char a, b, c;
        char new[100] = "expression";

        b = ({a = 3; new;})[0];
        c = (({a = 4; new;}), a, *(({a = 5; new;}) + 1));
        printf ("b:%c\n", b);
        printf ("c:%c\n", c);
        printf ("sizeof(p):%d\n", sizeof(p));
        printf ("sizeof(new):%d\n", sizeof(new));
        printf ("sizeof(new[0]):%d\n", sizeof(({a = 3; new;})[0]));
        printf ("sizeof(expression):%d\n", sizeof(({a = 3; new;})));

}
b:e
c:x
sizeof(p):8
sizeof(new):100
sizeof(new[0]):1
sizeof(expression):8

根据这一理解,b的等号右边是先算复合型语句,({a=3;new;}),值为new的值,由于new是数据名,也是指针常量,所以new的值是一个地址,数据类型为,(char *)类型,这时候下标表达式其实跟间接访问一致,最终值为new[0]的值为字符"e“。

C的等号右边是逗号表达式,逗号表达的值为最后一个表达式的值,所以最后表达式的值为new[1]

最下面的3个sizeof的打印值

第一个相当于类型(char *)的占得字节大小

第二个是new这个数组的长度(顺便说一句,数组名通常情况下是指针常量,只有在两种情况下不用指针常量表达,一个就是sizeof操作符,一个是单目操作符&,取一个数组名的地址是一个指向数组的指针)

第三个就是指new[0]占得字节大小

第四个就是这个表达式占得字节大小

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喝醉的鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值