嵌入式C语言入门——关键字&宏

预处理

宏函数

  • 避免了函数的入栈、出栈、跳转等开销,可以提高程序运行效率
  • 多次调用,会是代码变的庞大,以空间换时间
  • 避免替换错误需要添加括号
#define AAD(x, y) (x + y)
#define MAX(x, y) ( (x > y) ? (x) : (y) )

宏的有效范围

  • 从宏定义的位置开始到文件结束或者取消宏定义
  • 不做作用域检测
  • 不做类型检测
void test()
{
    #define NUM 10
}

int main()
{
    printf("%d\n", SUM);
}

撤销宏

#undef SUM

内置宏

printf("代码在 %d 行\n", __LINE__);
printf("代码编译的时间%s %s\n", __DATE__, __TIME__);
printf("文件名 %s\n", __FILE__);
printf("函数名%s\n", __FUNCTION__);

条件编译ifdef

#ifdef 标识符
    程序段1
#else
    程序段2
#endif
 
它的功能是:如果标识符已被#define命令定义过,则对程序段1进行编译;
否则对程序段2进行编译。如果没有程序段2(它为空),本格式中的#else可以没有,#endif不可或缺
#include <stdio.h>
 
int main()
{
  #ifdef _DEBUG
     printf ("正在使用DEBUG模式编译代码。。。\n");
  #else
     printf ("正在使用Release模式编译代码。。。。\n");
  #endif
 
  return 0;
}

编译的时候增加宏:gcc -D_DEBUG


#if 常量表达式
    程序段1
#else
    程序段2
#endif
它的功能是:如果常量表达式的值为真(非0),则对程序段1进行编译;
否则对程序段2进行编译。因此可以使程序在不同条件下编译,完成不同的功能。
#include <stdio.h>
// window  _WIN32
// Linux   __linux__
 
int main()
{
    #if (_WIN32)
    {
        printf("this is window system\n");
    }
    #elif (__linux__)
    {
        printf ("this is linux system\n");
    }
    #else
    {
        printf ("unkown system\n");
    }
    #endif
 
    #if 0
        code
    #endif
 
    return 0;
}

#与##

  • #用于在与编译期间将宏参数转化为字符串
#include <stdio.h>
 
#define SQR(x) printf ("The square of "#x" is %d \n", ((x)*(x)))
 
int main()
{
    SQR(8);
    return 0;
}
  • ##用于在预编译期间粘连两个符号
#include <stdio.h>
 
#define CREATEFUN(name1, name2)\
void name1##name2()\
{\
    printf ("%s called\n", __FUNCTION__);\
}
 
CREATEFUN(my, Function);
 
int main()
{
    myFunction();
    return 0;
}

关键字


Static

Static修饰局部变量

在局部静态变量前面加上关键字static,该局部变量便成了静态局部变量。静态局部变量有以下特点:
(1)该变量在全局数据区分配内存
(2)如果不显示初始化,那么将被隐式初始化为0
(3)它始终驻留在全局数据区,直到程序运行结束
(4)其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束

Static修饰全局变量

在全局变量前面加上关键字static,该全局变量变成了全局静态变量。
全局静态变量有以下特点:
(1)在全局数据区内分配内存
(2)如果没有初始化,其默认值为0
(3)该变量在本文件内从定义开始到文件结束可见,即只能在本文件内使用

Static修饰函数

在函数的返回类型加上static关键字,函数即被定义成静态函数。
静态函数有以下特点:
(1) 静态函数只能在本源文件中使用
(2) 在文件作用域中声明的inline函数默认为static
说明:静态函数只是一个普通的全局函数,只不过受static限制,他只能在所在文件内使用,不能在其他文件内使用。

extern

extern可置于变量或者函数前,以表示变量或者函数的定义在别的文件中,提示编译器遇到此变量或函数时,在其它模块中寻找其定义。

const

const只是不能通过修饰的变量改变空间的值,不代表空间的值不能改变

const修饰一般变量

一般变量是指简单类型的只读变量。这种只读变量在定义时,修饰符const可以用在类型说明符前,也可以用在类型说明符后。例如:
int const i = 2;
const int i = 2;

const修饰数组

定义或说明一个只读数组
int const a[5] = {1,2,3,4,5}; 
const int a[5] = {1,2,3,4,5};

const修饰指针

const int * p;             // p可变,p指向的对象不可变
int const * p;             // p可变,p指向的对象不可变
int * const p;             // p不可变,p指向的对象可变
const int * const p;       // 指针p和p指向的对象都不可变
 
这里给出一个记忆和理解的方法:
先忽略类型名(编译器解析的时候也是忽略类型名),我们看const离哪个近,离谁近就修饰谁。
const (int) *p   //const 修饰*p,p是指针,*p是指针指向的对象,不可变。
(int) const * p; //const 修饰*p,p是指针,*p是指针指向的对象,不可变。
( int) * const p;//const 修饰p,p不可变,p指向的对象可变
const ( int)* const p;  // 前一个const修饰*p,后一个const修饰p,指针p和p指向的对象都不可变

const修饰函数参数

const修饰也可以修饰函数的参数,当不希望这个参数值在函数体内被意外改变时使用,例如:
`void Fun(const int *p);`
告诉编译器*p在函数体中不能改变,从而防止了使用者的一些无意的或错误的修改。

const修饰函数返回值

const修饰符也可以修饰函数的返回值,返回值不可被改变。例如:
`const int Fun(void);`

typedef

使用关键字 typedef 可以为类型起一个新的别名,语法格式为:

typedef oldName newName;

oldName 是类型原来的名字,newName 是类型新的名字。
 
需要强调的是,typedef 是赋予现有类型一个新的名字,而不是创建新的类型。为了“见名知意”,请尽量使用含义明确的标识符,并且尽量大写。

typedef给结构体类型定义别名

typedef struct stu
{
    char name[20];
    int age;
    char sex;
} STU;
STU 是 struct stu 的别名,可以用 STU 定义结构体变量:
STU body1,body2;
它等价于:
struct stu body1, body2;

typedef给指针类型定义别名

typedef int (*PTR_TO_ARR)[4];

表示 PTR_TO_ARR 是类型int * [4]的别名,它是一个二维数组指针类型。接着可以使用 PTR_TO_ARR 定义二维数组指针:
PTR_TO_ARR p1, p2;

按照类似的写法,还可以为函数指针类型定义别名:
typedef int (*PTR_TO_FUNC)(int, int);
PTR_TO_FUNC pfunc;

typedef与#define区别

typedef 在表现上有时候类似于 #define,但它和宏替换之间存在一个关键性的区别。
正确思考这个问题的方法就是把 typedef 看成一种彻底的“封装”类型,声明之后不能再往里面增加别的东西。
 
1) 可以使用其他类型说明符对宏类型名进行扩展,但对 typedef 所定义的类型名却不能这样做。如下所示:
#define INTERGE int
unsigned INTERGE n;  //没问题
 
typedef int INTERGE;
unsigned INTERGE n;  //错误,不能在 INTERGE 前面添加 unsigned
 
2) 在连续定义几个变量的时候,typedef 能够保证定义的所有变量均为同一类型,而 #define 则无法保证。例如:
#define PTR_INT int *
PTR_INT p1, p2;
经过宏替换以后,第二行变为:
int *p1, p2;
这使得 p1、p2 成为不同的类型:p1 是指向 int 类型的指针,p2 是 int 类型。
 
相反,在下面的代码中:
typedef int * PTR_INT
PTR_INT p1, p2;
p1、p2 类型相同,它们都是指向 int 类型的指针。

猜你喜欢

转载自blog.csdn.net/qq_35599308/article/details/84666714