C语言进阶总结

c语言仅为开发unix而生 为高效而生
c++为面向对象语言而生 兼容已有的代码
系统一般由多种语言写成的


数据类型和变量:
数据类型是一个模子,操作变量就是操作空间
char short int
typedef用法:
typedef int INT32
typedef unsigned char BYTE
typedef struct _demo
{
short s;
BYTE  b1;
BYTE  b2;
INT32 i;
}DEMO;


属性关键词:
变量定义前可以加属性关键词
auto:
变量存储在程序的栈里 变量的值是变的
局部变量默认auto类型
static:
局部变量存储于程序的静态区
文件作用域标识符
修饰的全局变量作用域只在声明的文件当中
修饰的函数作用域只在声明的文件当中
register:
指明变量存储于寄存器里
只是请求寄存器变量 但不一定请求成功

register变量必须是CPU寄存器可以接受的值
不能用&获取register变量的地址

用在实时性能要求比较高的系统里

只会被初始化一次


语句用法:
if - else:(两路分支)
if的条件是逻辑上的值

bool型变量不能直接在条件里面进行比较
普通变量和0比较 0值应该出现在比较符号左边(避免BUG 防止写成赋值符号)
float不能直接进行0值比较 需要定义精度

switch:(多路分支)
case语句分支必须有break 否则会导致分支重叠
default语句有必要加上 以处理特殊情况

case 语句中的值只能是整型或字符型
顺序分析:
按照字母或者数字排列各条语句
正常情况放前边 异常情况放后面
default 语句只能用于处理真正的默认情况

if用于范围判断比较适合

循环语句:
do while for
do - while 至少执行一次
用do - while(0)在只执行一次的场合(申请内存 释放内存 避免内存泄漏)

使用while时一定要注意条件是什么


break 表示终止循环的执行 跳出块
continue 表示中值本次循环体 进入下次循环执行



关键字分析:
goto:
禁用goto 打入冷宫

void:
修饰函数的返回值和入口参数
不能定义变量类型

只有相同类型的指针才能相互赋值 void指针可以作为左值用于接收任意类型的指针

用void* 作为函数的入口类型可以接收任意类型的指针参数

extern:
声明外部定义的变量和函数
用于告诉编译器c方式编译 extern"C"

sizeof正名:
编译器内置的指示符 不是函数
计算相应的实体所占的内存大小
其值在编译期就已经知道结果了

sizeof int; 是不允许的
sizeof (int); 是允许的
所以统一写成了sizeof(); 被冤枉成为一个函数了

const:
const只对编译器有用 运行时无用
变量会占用内存空间 用指针操作地址还是可以改变值的  const类型的数组的值也会被改变
const修饰的变量是只读的 本质还是变量

const修饰指针:
const int* p;
int const* p;
int* const p;
const int* const p;

左数右指 不变
当const出现在*号左边时指针指向的数据为常量
当const出现在*号后右边时指针本身为常量

const修饰函数参数表示在函数体内不希望改变参数的值
const修饰函数返回值表示返回值不可变 多用于返回指针的情形

volatile:
编译器警告指示字
告诉编译器必须每次去内存中取变量值 不做优化
修饰可能被多个线程访问的变量
修饰可能被未知因数更改的变量

 
enum:
enum是一种自定义类型
enum默认常量在前一个值的基础上依次加1 第一个值默认为零 
enum类型的变量只能取定义时的离散值

define宏只是简单的替换 无法被调试 是一种特定类型的常量

typedef:
给一个已经存在的数据类型重命名
没有产生新的类型
不能进行signed unsigned进行拓展
 
define只是字符串的替换 无别名的概念


符号的技巧:
注释:
编译器在编译的时候 会将注释删除同时用空格替代
编译器认为双引号括起来的内容都是字符串 双斜杠也不例外
/*......*/ 型的注释不能被嵌套

/*作为一段注释的开始 直到遇见*/

准确易懂简洁 提示准确 阐述原因

接续符和转义符:
接续符 \:
指示编译器行为的利器 继续下一行的内容
注意加空格
接续单词的时候注意不能加空格

define必须在一行内结束 用接续符实现定义代码块

转义字符 \:
表示无回显字符 
\n 换行
\t tab

出现在字符或者字符串当中

单引号&双引号:
单引号 表示字符常量   代表整数
'a' 一字节
'a' + 1 = 'b'
双引号 表示字符串常量 表示一个指针
"a" 二字节
"a" + 1 = '\0' (指针操作)
不能将字符 和 字符串 赋值 和 比较

逻辑运算符:
短路规则:
||从左到右计算 为真停止
&&从左到右计算 为假停止

! :
"!" 只认得0 见到0 返回1
值不为0时 返回0

三目运算符:
逻辑判断之后 返回一个值 不是变量

位运算符:
避免位运算符 逻辑运算符 数学运算符同时出现在一个表达式里
尽量用()表达次序
左移n位 相当于乘于 2^n
右移n位 相当于除于 2^n

a ^ a = a;

操作符分析:
++:
i = 3; (++i) + (++i) + (++i) = 16 / 18;
i = 3; k = (++i, i++, i+10) = 15 //逗号表达式 从左到右计算 最后一个表达式的值

i +++ 1 
编译器从左到右尽可能多的包含字符

优先级和类型转换:
----------------------------------------------------------
常见问题 | 表达式
----------------------------------------------------------
.的优先级高于* ->可以消除这个问题  | *p.f
[]的优先级高于* | int *app[]
函数()高于* | int *fp()
== != 优先级高于 位操作 | (val & mask != 0)
== != 优先级高于 赋值符 | c = getchar() != EOF
算术运算符高于位移运算符 | mab << 4 + lsb
逗号运算符在所有运算符优先级最低 i = 1, 2;
----------------------------------------------------------

C语言的隐式类型转换:
低类型向高类型转换
实参向形参转换
赋值右边向赋值左边转换
return 表达式转换为返回值类型

char  -> int -> unsigned int -> long -> unsigned long -> double
  |
short -> float编译预处理
 
编译预处理:
编译过程:
预处理器 - 编译器 - 汇编器 - 链接器
gcc -E test.c -o test.i

gcc -S test.i -o test.s

gcc -C test.s -o test.o

单步编译技术 排除错误

链接器的工作就是把各个独立的模块链接为可执行程序
静态链接在编译器完成 动态连接在运行时完成

宏定义使用分析:
#define 从本行开始之后的代码可以使用这个宏常量
宏表达式像函数 却不是函数 比函数强大 容易出错
宏表达式只是简单的文本替换 有副作用
不要在宏参数里面写表达式
可以只充当一个语句 扩展C语言的用法
编译器不知道宏表达式的存在
用实参代替形参不进行任何计算 实参可以是只是数据类型
宏表达式没有调用开销
宏表达式不能出现递归的定义

#undef结束#define定义域

功能强大的内置宏
__FILE__ :打印文件名
__LINE__ : 不能放在函数里面来调用 可以使用宏代码块
日志宏   : 打印时间 包含<time.h> 

宏代码块 多条语句 多行:  do{} while(0)  +   续行符

条件编译使用分析:
#if
#else
#endif :
对编译器起作用 执行时不起作用

gcc -DC=1 -E test.c -0 test.i //命令行时 预编译时指明C=1

#include:
将已经存在的文件内容嵌入到当前文件夹
间接包含同样会产生嵌入文件内容的动作

所以用到
#ifndef
#define
#endif 
条件编译技术 只包含一次 防止多次展开 产生重定义的情况

应用:
不同的产品线用同一份代码
区分编译产品的调试版和发布版

#error 和 #line:
#error 编译指示字:
生成一个编译错误信息 停止编译
#error message 无需双引号
#warning message 生 成编译警告 不会停止编译
#line 编译指示字:
用于强制指定新的行号和编译文件名 并对源程序的代码重新编号
#line number filename filename可以省略
#pragma:
编译器指示字 用于指示编译器完成一些特定的动作
指示字是编译器和操作系统特有的
在不同的编译器之间是不可移植的
编译器将忽略不认识的指令
不同的编译器将以两种不同的方式解释同一条pragma指令

#pragma message
message 参数在大多数的编译器中有相似的功能
message 参数在编译时输出信息到编译输出窗口中
message 可用于代码的版本控制

知道编译的代码是不是自己想要的

#pragma pack
内存对齐 不同类型的数据在内存当中并不是一个一个顺序排放的
CPU对内存的读取并不是连续的 按块读取

只能读写偶地址

pragma(4) 告诉编译器的默认对齐方式
结构体成员的对齐参数为其所有成员使用的对齐参数的整数倍

#和##运算符使用解析:
预处理器的开始符
#用于在预编译期将宏参数转换为字符串
#存在于宏里面使用 打印调用的函数名

##用于在编译的时候粘连两个字符

##定义结构体类型
#define STRUCT(type) typedef struct _tag_##type type; struct _tag_##type




猜你喜欢

转载自blog.csdn.net/Mr_Ma_/article/details/80083495
今日推荐