十、 五种修饰函数的类型,typedef函数,宏定义,编译的过程,条件编译
1. const --》只读指针
1.修饰基本数据类型变量: const int a = 10; //修饰的变量必须初始化
//表示a为只读变量,不能修改
//a = 100; 编译会报错!!!
2.修饰指针变量:
第一种情况:
int a=10, b =200;
int * const p = &a; //必须初始化
p = &b; //编译会报错
*p = 300; //p指针解引用是可以的
第二种情况:
int a=10, b =200;
int const * p = &a; //必须初始化
p = &b; //可以
*p = 300; //p指针解引用编译会报错
第三种情况:
int a=10, b =200;
const int * p = &a; //必须初始化
p = &b; //编译会报错
*p = 300; //p指针解引用是可以的
第四种情况:
int a=10, b =200;
const int * const p = &a; //必须初始化
p = &b; //编译会报错
*p = 300; //p指针解引用编译会报错
2.volatile -->防止编译器优化变量
//单片机延时函数
void delay()
{
int i = 0x1000000; //可能会在编译时被编译器优化(删除)掉
while(i--);
}
//单片机延时函数
void delay()
{
volatile int i = 0x1000000; //编译器不会优化变量
while(i--);
}
3.auto和register
1、auto自动化变量(内存变量),定义变量时可以省略不写
int a; <==> auto int a;
2、register(寄存器变量) --》用在调用频繁的变量可以定义成一个寄存器变量
register int a; --》变量定义时分配的寄存器存储
注意:
1》定义寄存器变量是不一定成功(主要看编译器),如果不成功他会自动定义成自动化变量
2》寄存器变量没有内存地址
4.extern
1、概念:表示外部调用,从其他.c文件里面调用
2、使用方法:
1》修饰变量
extern int a; -->从其他文件调用这个变量,如果其他.c文件没有定义肯定会报错
2》修饰函数
extern int add(int a, int b); -->表示当前.c没有定义该函数,在其他.c里面定义了该函数,如果其他.c文件没有定义肯定会报错
注意:static修饰的变量或函数,都是只能用于当前这个.c; 该变量不能再被estern调用!!!
5.typedef --》给数据类型取别名
1、给基本数据类型取别名
typedef int INT; //给int取了一个别名叫INT
int a; 《===》 INT a;
2、给数组数据类型取别名
typedef int ARRAY[4]; //给数组类型为:int ()[4]取了一个别名叫做 ARRAY
3、给函数指针数据类型取别名
int add(int , int ); ---》对应的函数指针类型为:int (*)(int , int );
typedef int (*FUNC_P)(int , int );
//给函数指针int (*)(int , int )取别名叫FUNC_P
4》给结构体数据类型取别名
(1) 给结构体类型 struct student取了一个别名叫做STU,所以 struct student 《==》STU
1>
struct student
{
char name[15];
int num;
int age;
char sex;
}STU; 定义了一个结构体数据类型变量叫做STU
2>
typedef struct student
{
char name[15];
int num;
int age;
char sex;
}STU; //给结构体数据类型struct student 取了一个别名叫做 STU
struct student lisi; ==》STU lisi; //都是表示定义结构体变量
struct student *p; ==》STU *p; //表示定义结构体指针
3>
typedef struct student
{
char name[15];
int num;
int age;
char sex;
}STU, *STU_P; //给结构体数据类型struct student 取了一个别名叫做 STU
//给结构体数据类型struct student *(结构体指针)取了一个别名叫做 STU_P
struct student lisi; ==》STU lisi; //都是表示定义结构体变量
struct student *p; ==》STU *p; //表示定义结构体指针
struct student *p; ==》 STU_P p; //表示定义结构体指针
6.宏定义(又称之为宏替换,在代码编译阶段中的预处理阶段进行替换,不是在程序运行的过程中替换)
1.宏定义变量
#include <stdio.h>
#include <string.h>
#define MUN 20
#define LCD_W 800
#define LCD_H 480
int main(int argc, const char**argv)
{
int arry[MUN];
printf("%d\n", sizeof(arry));
int lcd_len = LCD_H*LCD_W;
printf("%d\n", lcd_len);
return 0;
}
注意:1》宏定义它是不需要分配内存
2》宏替换不能替换字符串里面的字符
2.带参宏 --》也是在编译阶段中的预处理阶段进行处理替换,它是和函数不同
带参宏与带参函数的5个区别:
带参宏 带参函数
处理时间 编译时 运行时
参数类型 无 需定义
程序长度 变长 不变
占用存储空间 否 是
运行时间 不占运行时间 调用和返回时占
7.编译的过程
把.c文件编译生成一个可执行文件,其实他是分为4个步骤:预处理、编译、汇编、链接
命令:gcc hello.c -o hello
1>预处理
预处理的编译命令:
gcc -E hello.c -o hello.i
作用:
(1)删除了注释代码
(2)展开了头文件
(3)处理了宏定义、带参宏、条件编译
2>编译
编译的编译命令:
gcc -S hello.i -o hello.s
作用:
(1)把C语言翻译成汇编语言
(2)检查代码语法错误
3>汇编
汇编的编译命令:
gcc -c hello.s -o hello.o
作用:
(1)把汇编语言翻译成机器码(二进制)
4>链接
编译命令:
gcc hello.o -o hello
作用:
链接要用到的函数库,把函数库的静态库编译到可执行文件里面,动态库在你要执行时再调用
8.条件编译
条件编译--》有选择的编译,一般用于代码调试,也是在编译阶段中的预处理阶段进行处理
命令:gcc test5.c -o test5 -DNUM -->-D 表示定义宏,例如:-DNUM表示定义宏NUM!!!
1》
#ifndef -->if not define ,如果没有定义某个宏,就会把代码编译到可执行文件
#ifndef NUM
//代码块
#endif
2》
#ifdef -->if define ,如果定义了宏,就会把代码编译到可执行文件
#ifdef NUM
//代码块
#endif
3》
#if 如果为真就会把代码编译到可执行文件
#if 1
printf("hello world\n");
#else
printf("good boy\n");
#endif
#include <stdio.h>
/***********************************************************************************/
关于程序拆分 --》即把一个复杂的.c文件拆分为多个.c / .h文件
例子: 将project.c文件拆分为project.c、add.c和add.h三个文件。
//函数声明
int add(int a, int b);
int reduce(int a, int b);
int main(int argc, const char**argv)
{
int num = add(100, 200);
printf("%d\n", num);
int num1 = reduce(300, 100);
printf("%d\n", num1);
return 0;
}
int add(int a, int b)
{
return a+b;
}
拆分效果:
gec@ubuntu:/mnt/hgfs/C语言/11/code/test/test$ cat project.c -n
1 #include <stdio.h>
2
3 //函数声明
4 extern int add(int a, int b);
5 int reduce(int a, int b);
6
7 int main(int argc, const char**argv)
8 {
9
10 int num = add(100, 200);
11 printf("%d\n", num);
12
13 int num1 = reduce(300, 100);
14 printf("%d\n", num1);
15
16 return 0;
17 }
gec@ubuntu:/mnt/hgfs/C语言/11/code/test/test$ cat add.c -n
1 #include "add.h"
2
3
4 int add(int a, int b)
5 {
6 return a+b;
7 }
gec@ubuntu:/mnt/hgfs/C语言/11/code/test/test$ cat add.h -n
1 #ifndef __ADD_H__
2 #define __ADD_H__
3
4 //要包含的头文件
5 #include <stdio.h>
6
7 //宏定义
8
9 //结构体数据类型
10
11 //全局变量
12
13
14
15
16 //函数声明
17 int add(int a, int b);
18
19
20 #endif
编译命令: gcc project.c add.c -o project 注意:编译的时候要注意加上所有你需要运行的文件名!!!
执行文件:./project
本文详细介绍了C语言中的修饰符,包括const、volatile、auto、register、extern和typedef的用法。讲解了它们如何影响变量、指针和函数的行为。此外,还提到了宏定义的作用和编译过程的四个步骤:预处理、编译、汇编和链接。最后,讨论了条件编译的概念及其在代码调试中的应用。
942

被折叠的 条评论
为什么被折叠?



