精华内容
下载资源
问答
  • 要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。
  • C语言宏定义函数

    万次阅读 多人点赞 2019-03-18 11:40:46
    通过一个比较函数的例子来说明宏函数和普通函数的区别: 宏函数形式: #define MAX( a, b) ( (a) > (b) (a) : (b) ) //这里为什么有这么多括号,后面会讲 普通函数形式: int max(int a, int b) { ...

    通过一个比较函数的例子来说明宏函数和普通函数的区别:

    宏函数形式:

    #define MAX( a, b) ( (a) > (b) (a) : (b) ) //这里为什么有这么多括号,后面会讲

    普通函数形式:

    int max(int a, int b)
    {
         return (a > b a : b)
    }

    宏函数

    优点:节省空间(给形参节省)

    缺点:浪费时间(主要浪费在编译时);没有语法检查,不安全。

    普通函数

    优点:有语法检查

    缺点:浪费空间。


    注意宏函数在调用时只是对函数中的变量做简单的替换,注意这里的替换真的是替换,非常死板的那种!!!

    可以看一下下面的例子:

    #define SQUARE_SUM(x,y) x*x+y*y
    #include <stdio.h>
    
    int main()
    {
        int i = 1,j = 2,k ;
        k = SQUARE_SUM(i+1,j);
        printf("%d",k);
        return 0;
    }

    很多人可能会这样算:2*2+2*2=8,这样其实是错误的。

    看一下程序运行的结果:

    原因是程序只是做了替换,也就是1+1*1+1+2*2=7

    现在知道为什么要在宏函数定义时加这么多括号了吧 (= =)

    想达到结果为8的效果应该这样写:

    #define SQUARE_SUM(x,y) (x)*(x)+(y)*(y) //注意这里的括号!!
    #include <stdio.h>
    
    int main()
    {
        int i = 1,j = 2,k ;
        k = SQUARE_SUM(i+1,j);
        printf("%d",k);
        return 0;
    }

    运行结果:

    OK! 大功告成!

    展开全文
  • 内联函数本质上是两个不同的概念如果程序编写者对于既要求快速,又要求可读的情况下,则应该将函数冠以inline
  • 写好C语言,漂亮的宏定义很重要,使用宏定义可以防止出错,提高可移植性,可读性,方便性 等等。
  • 要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。  在软件开发过程,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏...

        要写好C语言,漂亮的宏定义是非常重要的。宏定义可以帮助我们防止出错,提高代码的可移植性和可读性等。

      在软件开发过程中,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。

       宏定义中允许包含两行以上命令的情形,此时必须在最右边加上"\"且该行"\"后不能再有任何字符,连注释部分都不能有,下面的每行最后的一定要是"\","\"后面加一个空格都会报错,更不能跟注释。

      我们来看一个例子,比较两个数或者表达式大小,首先我们把它写成宏定义:

    #define MAX( a, b) ( (a) > (b) (a) : (b) )
    

      其次,把它用函数来实现:

    int max( int a, int b)
    
    {
    
    return (a > b a : b)
    
    }
    

      很显然,我们不会选择用函数来完成这个任务,原因有两个:首先,函数调用会带来额外的开销,它需要开辟一片栈空间,记录返回地址,将形参压栈,从函数返回还要释放堆栈。这种开销不仅会降低代码效率,而且代码量也会大大增加,而使用宏定义则在代码规模和速度方面都比函数更胜一筹;其次,函数的参数必须被声明为一种特定的类型,所以它只能在类型合适的表达式上使用,我们如果要比较两个浮点型的大小,就不得不再写一个专门针对浮点型的比较函数。反之,上面的那个宏定义可以用于整形、长整形、单浮点型、双浮点型以及其他任何可以用“>”操作符比较值大小的类型,也就是说,宏是与类型无关的。

      和使用函数相比,使用宏的不利之处在于每次使用宏时,一份宏定义代码的拷贝都会插入到程序中。除非宏非常短,否则使用宏会大幅度增加程序的长度。

      还有一些任务根本无法用函数实现,但是用宏定义却很好实现。比如参数类型没法作为参数传递给函数,但是可以把参数类型传递给带参的宏。

      看下面的例子:

    #define MALLOC(n, type) \
    
    ((type *) malloc((n)* sizeof(type)))
    

      利用这个宏,我们就可以为任何类型分配一段我们指定的空间大小,并返回指向这段空间的指针。我们可以观察一下这个宏确切的工作过程:

    int *ptr;
    
    ptr = MALLOC ( 5, int );
    

      将这宏展开以后的结果:

    ptr = (int *) malloc ( (5) * sizeof(int) );
    

      这个例子是宏定义的经典应用之一,完成了函数不能完成的功能,但是宏定义也不能滥用,通常,如果相同的代码需要出现在程序的几个地方,更好的方法是把它实现为一个函数。

      下面总结和宏和函数的不同之处,以供大家写代码时使用,这段总结摘自《C和指针》一书。

    【转】C语言中DEFINE简介及多行宏定义

    EXample

    define的单行定义

    #define max(a,b) (a>b?a:b)
    

    define的多行定义

    define可以替代多行的代码,例如MFC中的宏定义

    #define   MACRO(arg1,   arg2)   do   {   \ 
       \ 
    stmt1;   \ 
    stmt2;   \ 
       \ 
    }   while(0)
    

    关键是要在每一个换行的时候加上一个 "\ "

    //宏定义写出swap(x,y)交换函数
    #define swap(x, y)\
    x = x + y;\
    y = x - y;\
    x = x - y;
    
    自己写的一个小例子: 
    // 不能加 * ,因为指针也是一种类型
    
    #define  SORT( a,  n)\
    
    {\
    
        int i, j;\
    
        int *t = MALLOC(1,int);\
    
        for(i=0; i<n-1; i++)\
    
        {\
    
            for(j=0; j<n-1-i; j++)\
    
            {\
    
                if(*(a+j) > *(a+j+1))\
    
                {\
    
                    *t = *(a+j);\
    
                    *(a+j) = *(a+j+1);\
    
                    *(a+j+1) = *t;\
    
                }\
    
            }\
    
        }\
    
    }
    
    
    
    int main(int argc, const char * argv[])
    
    {
    
        int a=10, b= 120;
    
    
    
        int data[]={3,200,5};
    
        //swap(&a, &b);
    
        
    
       // sort(data, 3);     //和队列一样:会依据实参自动识别类型
    
        
    
        SORT(data, 3);     //会主动用实参代替形参识别类型
    
        
    
        for(int i=0;i<3;i++)
    
        cout << data[i]  << endl;
    
        
    
        
    
        //printf("%d   %d", a, b);
    
        return 0;
    
    展开全文
  • C语言_宏定义

    万次阅读 多人点赞 2019-02-02 00:20:03
      编译一个C语言程序的第一步骤就是预处理阶段,这一阶段就是发挥作用的阶段。C预处理器在源代码编译之前对其进行一些文本性质的操作,主要任务包括删除注释、插入被#include进来的文件内容、定义和替换由#...

    一.预处理

      编译一个C语言程序的第一步骤就是预处理阶段,这一阶段就是宏发挥作用的阶段。C预处理器在源代码编译之前对其进行一些文本性质的操作,主要任务包括删除注释、插入被#include进来的文件内容、定义和替换由#define 定义的符号以及确定代码部分内容是否根据条件编译(#if )来进行编译。”文本性质”的操作,就是指一段文本替换成另外一段文本,而不考虑其中任何的语义内容。宏仅仅是在C预处理阶段的一种文本替换工具,编译完之后对二进制代码不可见

    二.宏定义用法

    ①宏常量

      我们最常使用到的#define的用法就是用#define来定义一个符号常量,而要修改时,只需修改#define这条语句就行了,不必每处代码都修改
    例:

    #include"stdio.h"
    #define PI 3.14
    #define STR "圆周率约等于"
    int main()
    {
    	printf("%s %f",STR,PI); //预处理时会被替换为 printf("%s %f","圆周率约等于",3.14);
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述


    ②宏语句

      我们还可以用宏定义一条或多条语句
    例:

    #include"stdio.h"
    #define Print printf("hello world!")
    int main()
    {
    	Print;  //预处理时会被替换为 printf("hello world!");
    	return 0;
    }
    

    操作结果:
    在这里插入图片描述

    ③宏函数

      我还可以用宏来定义函数,因为宏定义也可以带参数
    例:

    #include"stdio.h"
    #define Print(str) printf("%s",str)
    int main()
    {
    	Print("这是一个只有一条语句的宏函数!");
        //预处理时会被替换为 printf("%s","这是一个只有一条语句的宏函数!")
    	return 0;
    }
    

    在这里插入图片描述

    ④其它

    1.#undef 是用来撤销宏定义的,用法如下:

    #define PI 3.141592654// code
    #undef PI
    //下面开始 PI 就失效了
    

    2.使用ifndef防止头文件被重复包含和编译

      这是宏定义的一种,它可以根据是否已经定义了一个变量来进行分支选择,一般用于调试等等.实际上确切的说这应该是预处理功能中三种(宏定义,文件包含和条件编译)中的一种----条件编译。 C语言在对程序进行编译时,会先根据预处理命令进行“预处理”。C语言编译系统包括预处理,编译和链接等部分。

    #ifndef x //先测试x是否被宏定义过
    #define x //如果没有宏定义下面就宏定义x并编译下面的语句
    ...
    ...
    ...
    #endif //如果已经定义了则编译#endif后面的语句
    

    条件指示符#ifndef检查预编译常量在前面是否已经被宏定义。如果在前面没有被宏定义,则条件指示符的值为真,于是从#ifndef到#endif之间的所有语句都被包含进来进行编译处理。相反,如果#ifndef指示符的值为假,则它与#endif指示符之间的行将被忽略。条件指示符#ifndef 的最主要目的是防止头文件的重复包含和编译。
      千万不要忽略了头件的中的#ifndef,这是一个很关键的东西。比如你有两个C文件,这两个C文件都include了同一个头文件。而编译时,这两个C文件要一同编译成一个可运行文件,于是问题来了,大量的声明冲突。

    所以还是把头文件的内容都放在#ifndef和#endif中吧。不管你的头文件会不会被多个文件引用,你都要加上这个。一般格式是这样的:

      #ifndef <标识>
    
      #define <标识>
    
      ......
    
      #endif
    

    <标识>在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h

    
      #ifndef _STDIO_H_
    
      #define _STDIO_H_
    
      ......
    
        #endif
    

    #ifndef xxx //如果没有定义xxx
    #define xxx //定义xxx
    #endif //结束如果
    这个用法主要是在头文件中,主要是为了防止类重复的include,所以在类的头文件之前加上前面两个,用类名替代xxx,在最后加上最后一句


    三.宏定义相关作用符

    ①换行符 "\"

      我们定义宏语句或者宏函数时不可能总是一条语句呀,那要是有很多条语句时怎么办?都写在一行吗?这样显然代码就不美观,可读性不好,所以有多条语句时,我们就在每行末尾(除了最后一行)加上"\",代表换行的意思
    例:

    #include"stdio.h"
    #define Print   printf("这是第1条语句\n");\
     		    	printf("这是第2条语句\n");\
     		    	printf("这是第3条语句\n")
     		    	
    #define Show(str1,str2,str3)\
    {\
    	printf("%s\n",str1);\
    	printf("%s\n",str2);\
    	printf("%s\n",str3);\	
    }
    int main()
    {
    	Print;  //无参数宏函数
    	Show("first","second","third"); //带参数宏函数
    	return 0;
    }
    

    操作结果:
    在这里插入图片描述

    ②字符串化符 "#"

      "#"是“字符串化”的意思,将出现在宏定义中的#是把跟在后面的参数转换成一个字符串
    例:

    #include"stdio.h"
    #define Print(str)\
    {\
    	printf(#str"的值是%d",str);\	
    }
    int main()
    {
    	int x=3,y=4;
    	Print(x+y); //此处等价于printf("x+y""的值是%d",x+y);
    	            //#str等价于"x+y",所以#str不需要再用双引号引起来 
    	return 0;
    }
    

    操作结果:
    在这里插入图片描述


    ③片段连接符"##"

      “##”是一种分隔连接方式,它的作用是先分隔,然后进行强制连接。在普通的宏定义中,预处理器一般把空格解释成分段标志,对于每一段和前面比较,相同的就被替换。但是这样做的结果是,被替换段之间存在一些空格。如果我们不希望出现这些空格,就可以通过添加一些##来替代空格。
    例:

    #include"stdio.h"
    #define Add(n,value)\
    {\
    	num##n+=value;\
     } 
    int main()
    {
    	int num1=1;
    	int num2=10;
    	Add(2,10); //等价于num2+=10; 这里把num和2连接成了num2 
    	printf(" num1=%d\n num2=%d",num1,num2); 
    	return 0;
    }
    

    操作结果:
    在这里插入图片描述

    四.宏函数的巧用

    ①类型传递

      我们知道函数虽然可以传递参数,但是却不能把类型作为参数传递,有时我们为了实现函数的复用性,就要使用STL模板,但是我们这个时候还有另外一种选择,就是写成宏函数
    例:
    一个开辟内存的函数

    #define Malloc(type,size) (type*)malloc(sizeof(type)*size)
    

    这个时候,我们只有把类型,容量作为参数传递进行,就可以开辟各种类型的内存了

    int *p=Malloc(int,100); //开辟int类型的内存
    char *q=Malloc(char,100); //开辟字符类型的内存
    

    ②传递数组

      由数组作为函数参数传递时,会失去其数组特性,也就是无法使用sizeof()函数计算出数组的大小,比如我们写一个排序函数,排序时我们不仅需要知道数组的首地址,还需要知道数组的大小,但是仅仅把数组名作为参数传递时,无法得知其数组大小,这时我们的函数就需要传递第二个参数,也就是数组的大小,于是函数就要写成Sort(int *a,int size).但宏函数就可以解决这个问题
    例:
    下面用宏函数写一个插入排序算法

    #include"stdio.h"
    #define InsertSort(list)\
    {\
    	int s=sizeof(list)/4;\
    	int i,j;\
    	for(i=2;i<=s;i++)\
    	{\
    		list[0]=list[i];\
    		for(j=i-1;list[j]>list[0];j--)\
    				list[j+1]=list[j];\	
    		list[j+1]=list[0];\		
    	}\ 
    }
    int main()
    {
    	int num[]={0,2,5,7,3,1,8,0,8,22,57,56,74,18,99,34,31,55,41,12,9,4};
    	InsertSort(num);
    	for(int i=1;i<sizeof(num)/4;i++)	
    		printf("%d ",num[i]);
    	return 0;
    } 
    

    操作结果:
    在这里插入图片描述
    当然还有很多宏定义的巧妙用法,这里就不全部列举了

    五.注意事项

    ① 运算符优先级问题

    #define MULTIPLY(x, y) x * y
    

      这是一个很简单的乘法函数,当计算MULTIPLY(10, 10),结果是100,这个大家都知道,但是当你计算MULTIPLY(5+5, 10)时,你以为结果还是100吗?当然不是,MULTIPLY(5+5, 10)=5+5*10=55,所以结果是55,所以我们写宏函数时要特别注意运算符的优先级,这里稳妥一点的写法应该这样写

    #define MULTIPLY(x, y) ((x)*(y))
    

    ②宏参数重复调用

    #define MAX(a,b) ((a)>(b)?(a):(b))
    int a=0;
    int b =1;
    int c =MAX(++a,++b);
    

    这里很多人都以为是c=MAX(1,2)=2;而实际上上面代码等价于

    int c =((++a)>(++b)?(++a):(++b));
    

    可以看到实际上a b都各自加了两次,所以c=1>2?2:3=3,所以结果是3

    ③分号吞噬问题

    #include"stdio.h"
    #define FUN(n)\
    {\
    	while(n>0)\
    	{\
    		if(n==3)\
    			break;\	
    	}\	
    }
    int main()
    {
    	int num=10;
    	if(num>0)
    		FUN(num);
    	else
    		num=-num;
    	return 0;
    }
    

      看似代码没有问题,但是一编译就报错,编译器显示"error: ‘else’ without a previous ‘if’",原来是因为FUN函数是一个代码块,然后if(num>0) FUN(num); 就等价于if(num>0) {…}; 这不就是在大括号后面打分号了吗?这样else当然就缺少if了
      这个时候我们可以用do{…}while(0)来解决这个问题,写成如下就没问题了,因为while()后面正好需要一个分号

    #define FUN(n)\ 
    do\
    {\
    	while(n>0)\
    	{\
    		if(n==3)\
    			break;\	
    	}\	
    }while(0)
    

    ④递归调用问题

    #define NUM (4 + NUM)
    

      按前面的理解,(4 + NUM)会展开成(4 + (4 + NUM)),然后一直展开下去,直至内存耗尽。但是,预处理器采取的策略是只展开一次。也就是说,NUM只会展开成(4 + NUM),而展开之后NUM的含义就要根据上下文来确定了。

    ⑤宏参数预处理

      宏参数中若包含另外的宏,那么宏参数在被代入到宏体之前会做一次完全的展开,除非宏体中含有#或##。

    有如下宏定义:

    #define A(y) X_##y
    #define B(y) A(y)
    #define SIZE 1024
    #define S SIZE
    

    A(S)会被展开成X_S。因为宏体中含有##,宏参数直接代入宏体。
    B(S)会被展开成X_1024。因为B(S)的宏体是A(S),并没有#或##,所以S在代入前会被完全展开成1024,然后才代入宏体,变成X_1024。

    展开全文
  • C语言宏定义用法大全

    2018-06-11 22:12:36
    关于C语言宏定义的用法,作了一个总结,除了常用宏定义外,还有类似函数的宏的用法
  • 文章目录一、typeof 关键字二、snprintf()函数的作用三、__builtin_expect的作用四、C语言中常用的预定义五、反斜杠的作用 一、typeof 关键字   如果你是 C++ 程序员,应该接触过 C++11 里的 decltype 操作符,它...

    一、typeof 关键字

      如果你是 C++ 程序员,应该接触过 C++11 里的 decltype 操作符,它的作用是自动推导表达式的数据类型,以解决泛型编程中有些类型由模板参数决定而难以(甚至不可能)表示的问题。其实这个特性在 C 语言中也早有类似的实现,GNU C 标准中的一个扩展特性 typeof 作用与 decltype 类似

    __typeof__ (ret) errnum = (ret); 
    

    二、snprintf()函数的作用

    #include<stdio.h>
    int snprintf(char* dest_str,size_t size,const char* format,...);
    

    【函数功能】:
      先将可变参数 “…” 按照format的格式格式化为字符串,然后再将其拷贝至dest_str中。

      如果格式化后的字符串长度小于size,则将字符串全部拷贝至dest_str中,并在字符串结尾处加上‘\0’; 如果格式化后的字符串长度大于或等于size,则将字符串的(size-1)拷贝至dest_str中,然后在字符串结尾处加上’\0’. 函数返回值是 格式化字符串的长度。

    三、__builtin_expect的作用

    __builtin_expect(errnum != 0, 0)
    

      这个指令是gcc引入的,作用是"允许程序员将最有可能执行的分支告诉编译器"。这个指令的写法为:__builtin_expect(EXP, N)。意思是:EXP==N的概率很大。一般的使用方法是将__builtin_expect指令封装为LIKELY和UNLIKELY宏。

    四、C语言中常用的预定义

    __LINE__:当前程序行的行号,表示为十进制整型常量
    __FILE__:当前源文件名,表示字符串型常量
    __DATE__:转换的日历日期,表示为Mmm dd yyyy 形式的字符串常量,
    Mmm是由asctime产生的。
    __TIME__:转换的时间,表示"hh:mm:ss"形式的字符串型常量,
    是有asctime产生的。(asctime貌似是指的一个函数)
    __STDC__:编辑器为ISO兼容实现时位十进制整型常量
    __func__:它指示所在的函数
    __assert_perror_fail:打印一条包含错误码ERRNUM的错误消息,并终止程序
    

    五、反斜杠的作用

      反斜杠起到换行作用,用于宏定义和字符串换行。其中宏定义中使用居多。如果一行代码有很多元素,导致太长影响阅读,可以通过在结尾加\的方式,实现换行,编译时会忽略\及其后的换行符,当做一行处理。

    #define CHECK_ACTION_RETURN(expr) \
        if (!expr) { \
            printf(":failed(%d)\n", ret); \
            return ret; \
                    } else { \
            printf(":ok\n"); \
                    }
    
    展开全文
  • 函数中替换为 ++MAX(a,b),则展开就成了 ++(a)>(b)?(a):(b),运算优先级也是错了。 (3)函数往往会导致较低的代码执行效率。 int a[]={9,3,5,2,1,0,8,7,6,4}; int max(n) { return n==0?a[0]:MAX(a[n]...
  • C语言位操作宏定义函数

    万次阅读 2021-06-18 15:48:54
    我们在写C语言时,经常需要用到位操作,但是每次自己使用逻辑运算符进行操作的时候,很费脑子,试试下面几个宏定义吧: #define GET_BIT(value,bit) ((value)&(1<<(bit))) //读取指定位 #define CPL_BIT...
  • C语言宏定义

    2020-12-29 11:24:09
    C语言宏定义C语言既具有高级语言的功能,又具有低级语言的许多功能。那么大家知道C语言宏定义是怎样的呢?下面一起来看看!宏定义是预处理命令的一种,它允许用一个标识符来表示一个字符串。先看一个例子:#include#...
  • 尽管函数宏定义和普通函数相比有很多缺点,但只要小心使用还是会显著提高代码的执行效率,毕竟省去了分配和释放栈帧、传参、传返回值等一系列工作,因此那些简短并且被频繁调用的函数经常用函数宏定义来代替实现...
  • C语言中宏定义

    千次阅读 2019-01-14 19:51:58
    C语言中宏定义
  •  在软件开发过程,经常有一些常用或者通用的功能或者代码段,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。  我们来看一个例子,比较...
  • C语言宏定义、宏函数、内置宏与常用宏

    万次阅读 多人点赞 2018-09-30 17:48:43
    C语言(C++)特有的两把双刃剑指针和宏定义/宏函数使得C语言在底层开发披荆斩棘、无所不能。这两个概念涉及范围比较广,其分支点也比较多,可谓星罗棋布,但这每颗星都足以照亮C语言因其开发周期、可维护性、可...
  • 宏定义中的参数称为形式参数,在宏调用的参数称为实际 参数。 对带参数的宏,在调用,不仅要宏展开,而且要用实参去代换形参。 带参宏定义的一般形式为: #define 宏名(形参列表) 字符串 在字符串含有各个...
  • C语言宏定义替代函数定义

    千次阅读 2014-06-13 20:18:24
    C语言宏定义替代函数定义 #include #define SWAP(a,b) {int t;t=a;a=b;b=t;} int main() { int a=1,b=2; printf("a=%d,b=%d\n",a,b); SWAP(a,b); printf("a=%d,b=%d\n",a,b); return 0; }
  • C语言基础--宏函数

    千次阅读 2020-06-07 15:43:45
    C语言基础–宏函数 1. 函数和数据类型 函数(宏函数)和函数类比会更加灵活,我们通过两个例子来看一下。 函数 #include <stdio.h> int sqr_int(int x) { return x*x; } double sqr_double(double x) { ...
  • C语言中一般用typedef来为回调函数定义别名(参数名)。 别名通过宏定义typedef来实现,不是简单的宏替换。可以用作同时声明指针型的多个对象。 比如: 代码如下:char *pa,pb;//pa是一个char型指针,但pb是一个...
  • 较大的C语言项目都会用大量的宏定义来组织代码,比较经典的代码就是Linux Kernel的头文件中用的宏定义。看起来宏展开就是做个替换而已,其实里面有比较复杂的规则,有关宏展开的语法规则此小结力图整理的比较全面。...
  • 是的,你没有听错,带参数的函数一样,同样支持可变参数。下面通过一个小程序加以说明。#include#include#define OUTSCREEN(msg, ...) printf(msg,__VA_ARGS__)int main(int argc, char* argv[]){OUTSCREEN(...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 99,819
精华内容 39,927
关键字:

c语言中的宏定义函数

c语言 订阅