当前位置:   article > 正文

嵌入式C语言的高级使用(全网最详细)_嵌入式c语言高级

嵌入式c语言高级

嵌入式C语言的高级使用(全网最详细)


一、宏

宏,在我看来是一个C语言中的一大特色,在此基础上可以使用一些特殊的功能。

1.1 变类型参数宏

在一些运用场景下,我们常常要用到类似于二者求最大、最小值,常常将这样的简单的一个功能封装为一个方法函数,但在函数的语法中,要明确定义参数的变量类型,也就是不同类型的变量需要建立相对不同的函数,但我们使用一些特殊的手段,就可以用宏实现不定类型的带参宏。见如下例子:

#define max(x,y)({\
	typeof(x) _x = (x);\
	typeof(y) _y = (y);\
	(void)(&_x == &_y);\
	_x > _y? _x:_y;})

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

没错就是这样一个带参宏就可以实现,任意变量类型求最大值的功能。

  • 首先我们来解析一下,这段代码的部分功能。

typeof:获取一个变量的变量类型。

(void)(&_x == &_y):这一句代码仅仅用来提醒用户两个变量类型是否一致。

__x > _y? _x:_y;:返回最后的结果。

二、可变参数

### 2.1可变参数的简单使用

对于可变参数,我们其实很熟悉,但你可能还不知道。大家还记得一开始学习C语言的时候敲的第一行代码吗?没错就是

printf("hallo wolrd!")

  • 1
  • 2

其实printf函数就是使用可变参数实现的,我们看一个例子:

printf(char *fmt,...); 	//这是printf函数的原型
int count = 10;
char sex = 'L';
printf("%d,%c",count,sex);

  • 1
  • 2
  • 3
  • 4
  • 5
  • fmt : 格式字符串。
  • . . . :对应多个参数。

实现可变参数需要添加头文件stdarg.h

  • va_list:实际上是一个char*类型。
  • va_start(fmt,args):根据参数args的地址,获取args参数后面的地址,并保存在fmt指针变量中。
  • va_end(args):释放args指针,将其赋值为NULL。

下面使用一个经典而又简单的例子来看一下用法。

#include <stdarg.h>

void printArray(int count,...)
{
    char var;
    int gap,i;
    /*创建了一个指向参数的指针*/
    va_list args;
    /*初始化指针*/
    va_start(args,count);
	/*对不定参数进行解析*/
    for( i = 0 ; i < count ; i++)
    {
        printf("*args %d = %d\n",count,*(int*)args);
        gap = (int)(sizeof(count)/sizeof(var));	//获取指针应该跳过的字节数
        args += gap;
    }
	/*使用完成后释放指针为NULL*/
    va_end(args);
}
void main(void)
{
    printArray(4,1,2,3,4);
    printArray(5,1,2,3,4,5);
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

最终我们可以看到后面的参数一个个被打印出来

2.2 调试

我们在写程序的时候,常常需要打印一些日志。不同的情况下需要打印不同的东西,所以我们常常会有一个调试的模块,下面是使用不定参数实现的一个简单的调式模块程序,如下:

#include <stdarg.h>
#include <stdio.h>

/* 用户需要配置的地方 */
#define USER_DEBUG_LEVEL 3
/*
    ERROR:错误等级的日志    
    WARNIG:警告等级的日志
    DEBUG:调式等级的日志
*/
#if USER_DEBUG_LEVEL>=3
    #define ERROR
#endif 
#if USER_DEBUG_LEVEL >= 2
    #define WARNING
#endif 
#if USER_DEBUG_LEVEL >= 1
    #define DEBUG
#endif 

void printfError(char* fmt ,...)
{
    va_list args;
    va_start(args,fmt);
    #ifdef ERROR
        vprintf(fmt,args);
    #endif 
    va_end(args);
}
void printfWarning(char* fmt ,...)
{
    va_list args;
    va_start(args,fmt);
    #ifdef WARNING
        vprintf(fmt,args);
    #endif 
    va_end(args);
}
void printfDebug(char* fmt ,...)
{
    va_list args;
    va_start(args,fmt);
    #ifdef DEBUG
        vprintf(fmt,args);
    #endif 
    va_end(args);
}
void main(void)
{
    printfError("Error\n");
    printfWarning("Warning\n");
    printfDebug("Debug\n");
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

不同的调试等级对应了不同的打印数据,可用于调试。

三、内联函数

内联函数是在编译后将函数体中的内容填充到函数调用的地方,而在运行的时候不用调用函数本身,而是直接执行函数体内的语句。但声明为内联函数,最终是否是内联函数是不确定的。

来看一个简单的例子,如下:

inline int sum(int a ,int b)
{
    return a + b;
}

void main(void)
{
    printf("sum = %d",sum(5,6));
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

返回结果一目了然,在普通函数中是调用sum()函数,然后返回。而内联函数是将 a+b 填充到了函数名的位置如下,形参作用周期在函数语句运行器件。

内联如下:

inline int sum(int a ,int b)
{
    return a + b;
}
void main(void)
{	
    {
       int a = 5,b = 6;
 	   printf("sum = %d",a + b);
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

函数体本身替代原有函数调用的地方。

关注公众号,获取本文的代码以及单片机调试中的一些工具
  • 1

请添加图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/587725
推荐阅读
相关标签
  

闽ICP备14008679号