先上代码,对于基于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;})));
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]占得字节大小

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

先上代码,对于基于f-statck协议栈改进项目时候,看到一段代码,内核里面的很多宏也经常使用这种复合型语句,看了相关的资料和博客,写下来自己的理解:static int (*real_clock_gettime) (clockid_t , struct timespec *);#define SYSCALL(func) ... 学完第四章后,便马不停蹄的开始第五章循环了,一是为了解决之前好多不懂得问题,可以用这一章的知识解决,二也是问了一下其他学计算机的大一同学,快的已经学指针了,慢的也到数组了,所以我得加快步伐,现在的自学进度还是太慢。 在学习这一章之前呢,我被推荐了一个新的编译工具visual studio 2019,所以以下程序都是在vs 2019上面跑的,之前的vc++ 6.0成为了时代的眼泪,但因为刚接触vs 2019,也要熟悉一段时间新的环境。 话不多说,直接开始跑步进入第五章。 注:本博客所有知识点均出自C程序 可以没有{},此时于while()后第一个分号 “;” 前面的语句就是循环体。 可以同时有{}和分号“;” , 也就是说,当有括号 {} 结尾可不需要分号, 当然你加了不也会出错,但不要while(); 【总结】在C语言中,用;和{}的作用都是一个:用于语句分隔,告诉编译器当语句遇到;或者{}中的 “}”时,说明执行该语句结束。所以说有点二选一的... 所以括号肯定是用在函数之中,包括函数中的各种流程控制语句中。 实际上,C程序中括号{}的作用:就是把多个单条语句用括号{}括起来组成一个结构上可以认为是一个语句的复合语句。 所以在程序中,我们应该把复合语句看成是单条语句,而不是多条语句,这种效果也可以用来区分程序的层次结构。所以括号都是成对出现的。否则,程序就会... 1. 遍历字符串中的每一个字符。 2. 如果字符是左括号(包括圆括号、方括号括号),则将其压入栈中。 3. 如果字符是右括号,则将栈顶元素弹出并与该右括号进行匹配。 - 如果匹配成功,则继续遍历字符串中的下一个字符。 - 如果匹配失败,则说明该字符串中存在不匹配的括号,直接返回不匹配的结果。 4. 如果遍历完整个字符串后,栈为空,则说明该字符串中所有括号都匹配,返回匹配的结果;否则返回不匹配的结果。 以下是使用C语言实现括号匹配检验的代码示例: #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char data; struct Node* next; } Node; typedef struct { Node* top; int size; } Stack; void push(Stack* s, char data) { Node* node = (Node*) malloc(sizeof(Node)); node->data = data; node->next = s->top; s->top = node; s->size++; char pop(Stack* s) { if (s->top == NULL) { printf("Stack is empty.\n"); exit(1); char data = s->top->data; Node* node = s->top; s->top = node->next; free(node); s->size--; return data; int isEmpty(Stack* s) { return s->top == NULL; int isMatch(char left, char right) { return (left == '(' && right == ')') || (left == '[' && right == ']') || (left == '{' && right == '}'); int isValid(char* s) { Stack stack = {NULL, 0}; for (int i = 0; i < strlen(s); i++) { char c = s[i]; if (c == '(' || c == '[' || c == '{') { push(&stack, c); } else if (c == ')' || c == ']' || c == '}') { if (isEmpty(&stack)) { return 0; char left = pop(&stack); if (!isMatch(left, c)) { return 0; return isEmpty(&stack); int main() { char* s1 = "(([]){})"; char* s2 = "([)]"; char* s3 = "]"; printf("%s: %s\n", s1, isValid(s1) ? "Valid" : "Invalid"); printf("%s: %s\n", s2, isValid(s2) ? "Valid" : "Invalid"); printf("%s: %s\n", s3, isValid(s3) ? "Valid" : "Invalid"); return 0; 上述代码中,我们定义了一个栈结构体,并使用链表来实现栈的基本操作(包括入栈、出栈和判断栈是否为空