先上代码,对于基于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;
上述代码中,我们定义了一个栈结构体,并使用链表来实现栈的基本操作(包括入栈、出栈和判断栈是否为空