C部分语法
C语言解释
记录自己在看代码时遇到C语言的语法
C语言编译系统
-
预处理
-
- 宏定义 #define
- 文件包含 #include
- 条件编译 #ifndef ······ #endif
-
编译
-
链接
.h和.c文件
.h文件是头文件,内含函数声明、宏定义、结构体定义等内容
.c文件是程序文件,内含函数实现,变量定义等内容。
#include xx.h 本质就是一些函数声明、宏定义、结构体定义等,只是它使用#include xx.h,这样就不用再每次重新写一遍这些声明了
反斜杠 \
C语言中反斜杠的作用是换行,为了好看的,阅读起来方便的:
- 字符串中换行
"this \
is \
for \
testing"
和"this is for testing"是相同的
- 宏定义中换行
在宏定义中要换行就必须使用 \ 结尾
#define CHECK_ACTION_RETURN(expr) \
if(!expr) { \
printf(":failed(%d)\n", ret); \
return ret; \
} else{ \
printf(":ok\n"); \
}
- 语句换行
在语句中换行作用不大,不写也没事
printf("this is for test %d %d %d\n",\
test_output_a,\
test_output_b,\
test_output_c);
printf("this is for test %d %d %d\n",
test_output_a,
test_output_b,
test_output_c);
是完全没区别的
带 井号 #的那些东西
#include
#define 标识符 常量
- 凡是以“#”号开头的均是预处理指定。预编译又称预处理。预编译不是编译,而是编译前的处理。这个操作是在正式编译之前由系统自动完成的。
- 预处理指令不是语句,所以后面不能加分号。
- 预处理所执行的操作就是简单的“文本替换”。对宏定义而言,预编译时会将程序中所有出现“标识符”的地方全部用这个“常量”替换,称为“宏替换”或宏展开。替换完了之后再进行正式的编译。所以说当单击“编译”时实际上执行了两个操作,即先预编译,然后才正式编译。
- #include
也是这样的,即在预处理的时候先单纯地用头文件stdio.h中所有的“文本”内容替换程序中#include 这一行,然后再进行正式编译。
#define
#define 定义一个标识符来表示一个常量。也称宏定义,标识符为所定义的宏名,简称宏。宏所表示的常量可以是数字、字符、字符串、表达式。
语法:#define 标识符 常量
特点:定义的标识符不占内存,只是一个临时的符号,预编译后这个符号就不存在了。
作用:宏定义最大的好处就是方便程序的修改。使用宏定义可以用宏代替一个在程序中经常使用的常量。当需要改变这个常量的值时,就不需要对整个程序一个一个修改,只需要修改宏定义中的常量即可。且当常量比较长时,使用宏就可以用较短的有意义的标识符来代替它,这样变成时更方便,不会出错。
#ifndef #endif
#ifndef : if not define,它是预处理功能(宏定义、文件包含和条件编译)中的条件编译
#ifndef的目的是放置头文件的重复包含和编译。
假设在头文件xx.h里有很多宏定义,如果在两个C文件中都include了xx.h头文件,那么在编译时就会发生声明冲突。所以我们要把头文件的内容都放在#ifndef和#endif中。不管你的头文件是否会被多个文件引用,都要加上这个。
基本格式:
#ifndef<标识>
#define<标识>
············
#endif
标识的命名规则:一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线。如stdio.h
#ifndef STDIO_H
#define STDIO_H
······
#endif
//c语言在对程序进行编译时,会先根据预处理命令进行预处理,C语言编译系统包括预处理,编译和链接等部分。
#ifndef X //先测试是否被宏定义过
#define X
程序段1//如果X没有被宏定义过,定义X,并编译程序段1;
#else
程序段2 //如果X已经定义过了则编译程序段2 的语句,忽视程序段1.
#endif
逻辑运算 与或非
- 与 &&
- 或 ||
- 非 !
位运算符 与或非异或
- 与 &
- 或 |
- 非 ~
- 异或 ^
0的二进制是00
1的二进制是01
2的二进制是10
3的二进制是11
0&3 为假 0|3 为真
typedef
typedef是为现有的类型起一个别名,使使用起来更加方便,注意它并没有产生新的类型。
示例1:
typedef int BOOL;//为int型起了一个新的别名叫BOOL
#define TRUE 1
#define FALSE 0
BOOL flag = TRUE;
示例2:结构体
typedef struct student{
char cname[20];
int iNumber;
struct studeng *next;
}LinkList;
LinkList *head;
以上定义了一个新的结构体,并将结构体起了一个新的别名LinkList.
typedef struct用法
先从结构体说起
定义结构体方法1
//定义结构体
struct Student{
int age;
char s;
}
//创建结构体变量
struct Student st1;
定义结构体方法2
//定义结构体 给结构体Student定义了一个别名Stu
typedef struct Student
{
int age;
char s;
}Stu;
//定义结构体变量
Stu st1;
定义结构体方法3
typedef struct{
int age;
char s;
}Stu;
//定义结构体变量
Stu st1;
以上三种方法对比可以看到,第三种方法最方便。
static关键字
static关键字有隐藏的功能。
静态局部变量
- 什么是局部变量?
局部变量就是在函数体里面定义的变量。编译器不会对局部变量初始化,除非对局部变量显式地赋值,否则局部变量的初始值是不确定的。
局部变量存储于进程栈空间,使用完毕就会释放
- 什么是静态局部变量
静态局部变量是在函数体里面定义的变量,有static关键字修饰。静态局部变量存储在全局数据区,即使函数返回,它的值也会保持不变。即使没被赋初值,编译器会自动地给它初始化为0。
静态局部变量存储在全局数据区;
未赋初值时编译器会对其自动初始化为0;
函数使用完毕,值会保持不变。
示例:局部变量与静态局部变量对比
#include
void fn(void)
{
int n = 10;//局部变量n
printf("n=%d\n", n);
n++;
printf("n++=%d\n", n);
}
void fn_static(void)
{
static int n = 10;//静态局部变量n
printf("static n=%d\n", n);
n++;
printf("n++=%d\n", n);
}
int main(void)
{
fn();
printf("--------------------\n");
fn_static();
printf("--------------------\n");
fn();//当再次调用该函数时,局部变量值不会保留,n =10
printf("--------------------\n");
fn_static();//当再次调用该函数时,静态局部变量值上次结果为11,会保留上次的结果,所以n=11
return 0;
}
执行结果:
n=10
n++=11
--------------------
static n=10
n++=11
--------------------
n=10
n++=11
--------------------
static n=11
n++=12
静态全局变量
- 什么是全局变量?
全局变量就是定义在函数体外的变量,它存储在全局数据区,且编译器会自动对其初始化。对整个工程可见。其他文件可以使用extern外部声明后直接使用。其他文件不能再定义一个同名的变量了。
全局变量存储在全局数据区,编译器会自动对其初始化
对整个工程可见,其他文件可以使用extern外部声明后直接使用。
- 什么是静态全局变量?
静态全局变量是定义在函数体外的变量,加上关键字static修饰。仅对当前文件可见,其他文件不可访问。所以其他文件可以有同名的静态全局变量,互不影响。
在定义不需要与其他文件共享的全局变量时,加上static关键字能够有效地降低程序模块之间的耦合,避免不同文件同名变量的冲突,且不会误使用。
静态函数
在函数的返回类型前加static,就是静态函数。
- 静态函数只能在声明它的文件中可见,其他文件不能引用该函数
- 不同的文件可以使用相同名字的静态函数,互不影响
非静态函数可以在另一个文件中直接引用,甚至不必使用extern声明。
示例:使用static声明的函数不能被另一个文件引用
/* file1.c */
#include
static void fun(void)
{
printf("hello from fun.\n");
}
int main(void)
{
fun();
fun1();
return 0;
}
/* file2.c */
#include
static void fun1(void)
{
printf("hello from static fun1.\n");
}
返回结果:
/tmp/cc2VMzGR.o:在函数‘main’中:
static_fun.c:(.text+0x20):对‘fun1’未定义的引用
collect2: error: ld returned 1 exit status
修改文件,不使用static修饰符,可在另一文件中引用该函数:
/* file1.c */
#include
void fun(void)
{
printf("hello from fun.\n");
}
/* file2.c */
int main(void)
{
fun();
return 0;
}
返回结果:
-> % ./a.out
hello from fun.
总结
| 函数体 | 当前文件 | 整个工程 | |
|---|---|---|---|
| 局部变量 | √ | ||
| 静态局部变量 | √ | ||
| 全局变量 | √ | √ | |
| 静态全局变量 | √ | ||
| 函数 | √ | √ | |
| 静态函数 | √ |
结构体
在C编译器下,结构体内不允许包含static变量。
C中struct只是类型声明,没有内存空间的分配,而static变量是需要分配内存的。
========================================================================
未完待续。。。。。