知识点一:gcc编译过程
预处理:头文件包含、宏替换、条件编译、删除注释 不做语法检查
编译:将预处理后的文件生成汇编文件语法检查
汇编:将汇编文件编译二进制文件
链接:将众多的二进制文件+库+启动代码生成可执行文件
知识点二:头文件包含
符号:
<>:用于包含系统的头文件
" ":用于包含用户自定义的头文件
#include <hehe.h>表示从系统的指定目录下寻找 hehe.h
#include "hehe.h"表示先从源文件所在的目录寻找如果找不到再到系统指定的目录下找
知识点三:宏定义
宏名 一般是大写
1、不带参数宏
形式:#define 宏名 需要代替的内容
宏只在当前源文件有效,定义宏是后面不能加 ; 号
#define N "hehe"
void test01()
{
//在预处理阶段 "hehe"替换 代码中所有出现的N ( 宏展开)
printf("%s\n",N);
return;
}
终止宏的作用范围:
形式:#undef 宏名
2、带参数的宏 (宏 函数)
形式:#define 宏名(参数1,参数2, …) 需要代替的内容
//宏的参数a b 不能写类型
//#define MY_ ADD(int a, int b) a+b //错误
#define MY_ADD(a,b) a+b
//调用宏名(参数)
MY_ ADD(10,20); // 10+20
加小括号
#define MY_MUL1(a,b) a*b
#define MY_MUL2(a,b) ((a)*(b))
void fun1(void)
{
printf("MY_MUL1 = %d\n",MY_MUL1(10,20)); //200 //MY_ MULI (10,20)==10*20
//MY MUL1 ( 10+10 , 20+20 )==10+10*20+20
printf("MY_MUL1 = %d\n",MY_MUL1(10+10,20+20)); //230 //不能保证完整性
//MY_MUL2(10+10, 20+20) ==((10+10)*(20+20))
printf("MY_MUL2 = %d\n",MY_MUL2(10+10,20+20)); //800 //保证完整性
}
3、带参数的宏(宏函数)和普通函数的区别
带参数的宏(宏函数):调用多少次就会展开多少次,执行代码的时候没有函数调用的过程,也不需要函数的出入栈,所以带参数的宏浪费空间节省了时间
代参的函数:代码只有一份,存在代码段,调用的时候去代码段读取函数指令 ,调用的时候要压栈(保存调用函数前的相关信息),调用完出栈(恢复调用函数前的相关信息),所以函数浪费了时间节省空间
知识点四:条件编译
如果xxx为真则运行语句1,为假运行语句2。
//通过条件编译控制大小写的转换
#include<stdio.h>
int main(int argc,char *argv[])
{
char buf[128] = "";
printf("请输入字符串");
// fgets 会获取换行符
fgets(buf,sizeof(buf),stdin);
int i = 0;
//去掉换行符 strlen返回的是字符串是长度 不包含'\0'
//strlen(buf)-1 这是换行符的下标位置
buf[strlen(buf)-1] = '\0';
//buf[i]是取数组中的第i个元素的值。
//while(buf[i] != '\0')
while(buf[i]) //最后一一个元素是'\0' == 0==假循环进不去
{
#if 1
if(buf[i]>= 'A' && buf[i]<='Z')
buf[i] = buf[i]+32;
#else
if(buf[i]<= 'a' && buf[i]<='z')
buf[i] = buf[i]-32;
#endif
i++;
}
printf("buf = %s\n",buf);
}
知识点五、防止头文件重复包含
方式一:#pragma once 编译器决定
#pragma once 放在头文件的最前方
方式二:c/c++的标准制定
#ifndef __头文件名_H__ //大写
#define
//头文件具体内容
#endif
总结:
#pragma once 编译器决定强调的文件名
#ifndef c/c++标准制定强调的宏而不是文件
知识点六:原码、补码、反码
负数在计算机中存储的是补码
注意:无符号数,正数,他们的原码 == 反码 == 补码
负数:反码 = 原码的符号位不变其他位取反
补码 = 反+1
计算机为啥要补码?
如果没有补码:
6-10 == -4
6+(-10) == -4
0000 0110
1000 1010
————————————————————————
1001 0000 == -16 (错误)
如果有补码:
0000 0110
1111 0110
--------------------------------------- 补码转原码:取反加一
1111 1100----->1000 0011—>1000 0100 ==> -4
总结:补码的意义.将减法运算变加法运算
以1字节分析:
有符号符: 1111 1111 ~ 1000 0000~0000 0000 ~ 0111 1111
-127 ~ -0 ~ +0 ~ +127
计算机为了扩数据的表示范围:故意将 -0 看成-128
-128~127
无符号数:0000 0000 ~ 1111 1111 == 0~255
总结:补码统一 0 的编码
+0 == 0000 0000==0000 0000 (反码) ==0000 0000 (补码)
-0 == 1000 0000 ==1111 1111 (反码) ==0000 0000 (补码)
知识点七:计算机对数据的 存储 与 读取
存储:
void test01 ()//存储
{
//负数 以补码存储
char data = -10;
//正数 以原码存储
char data2 = 10;
//十六进制以原码存储(
char data3 = 0xae; //Oxae==1010 1110
//八进制 以原码存储
char data4 = 0256; //0256==1010 1110
//每3位二进制代表一位八进制
//如果数据越界 以原码 存储
char data5 = 129; // 1000 0001
unsigned char data6 = -10; //0000 1010
//取%x %u %o都是输出内存的原样数据
//每4位二进制 代表一位十六进制 (记住)
printf("%x \n",data); //0xf6==1111 0110
printf("%x\n",data2); //0x0a ==0000 1010
printf("%x\n",data3); //0xae
printf("%x\n",data4); //0xae
printf("%x\n",data5); //0x81
printf("%x\n",data6); //0xfb
}
读取:
void test02 ()
{
char data1 = -10; //-10 == 1000 1010
char data2 = 10;
//取:%d %hd %ld有符号取%u %x %o %lu都是无符号取
//有符号取:%d %hd %ld
//首先看内存的最高位如果为1 将内存数据符号位不变取反+1到原码
//最高位如果为0将数据原样输出。
//无符号取:将内存数据原样输出
printf("%d\n", data1) ;//-10
//datal & 0x000000ff只取低8位
printf ("%u\n", data1 & 0x000000ff) ;//246==1111 0110
printf("%d\n",data2);
}