GCC
GCC是一个编译器,可以将C语言代码编写为机器码。
支持C/C++,Go,Fortran等语言。
支持MacOS,Windows,Linux等平台。
上述代码:将main编译成一个名字叫main的可执行程序。
%d代表数值,%p代表地址。
指针
*一级指针
指针,比如定义一个指针变量,那个这个指针变量代表的就是另一个变量的地址。
比如:
1 2 3 4 5 6 7 8
| int main(){ int a=10; int *b=&a; printf("a=%d"\n,a); printf("b=%p"\n,b); printf("*b=%d"\n,*b); return 0; }
|
打印出的效果:
a=10,代表数值。
b=ox16db88b58,代表地址。
*b=10,这里因为b本身就是指针变量, *b是解引用指针,他可以获取b指针指向的那块内存地址里存储的值。
**二级指针
1 2
| int **c=&b; printf("a=%d"\n,**c);
|
打印出的效果:
a=10,这是两次解引用。
数组
一维数组
1 2 3 4 5 6 7 8
| int main(){ int a[5]={1,2,3,4,5} for(int i=0;i<5;i++) { printf("a[%d]=%d"\n,i,a[i]); } return 0; }
|
打印出的效果:
a[0]=1;
a[1]=2;
a[2]=3;
a[3]=4;
a[4]=5;
二维数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| int a[3][4]={ {1,2,3,4} {5,6,7,8} {9,10,11,12} } int main() { for(i=0;i<3;i++) { printf("\n"); for(j=0;j<4;j++) { printf("a[%d][%d]=%d\t",i,j,a[i][j]); } } return 0; }
|
打印出的效果:

其中,\t代表智能制表符,能让数据排列更好看。
指针和数组
首先,指针可以直接赋到一个数组上,天然的指向这个数组的第一个元素的地址。同时解引用该指针,就会得到数组的第一个元素的值。
1 2 3 4 5 6 7 8 9 10
| int main(){ int a[5]={1,2,3,4,5}; int *p=a; printf("a的第一个元素的地址是%p\n",p); printf("a的第一个元素的值是%d\n",*p); p=p+1; printf("a的第二个元素的地址是%p\n",p); printf("a的第二个元素的值是%d\n",*p); return 0; }
|
输出的结果如下:

其中int类型占四个字节,所以a数组中前后两个元素的地址差是4。
static
函数内部的局部变量前面加上static,就会使这个变量在函数结束后,变量的值保留修改,直到整个程序结束,这个局部变量才回归到原本的初始值。
1 2 3 4 5 6 7 8 9 10
| void test(){ int a=1; a=a+1; printf("a=%d\n",a); } int main(){ test(); test(); return 0; }
|
输出的结果是:
a=2;
a=2;
若在int前面**加上 静态变量static**
1 2 3 4 5 6 7 8 9 10
| void test(){ static int a=1; a=a+1; printf("a=%d\n",a); } int main(){ test(); test(); return 0; }
|
输出的结果:
a=2;
a=3;
typedef
给现有的数据类型起一个“别名”(绰号)。
在STM32库函数stm32f10x_gpio.h中,有一段:
1 2 3 4 5 6
| typedef struct { uint16_t GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; }GPIO_InitTypeDef;
|
用typedef 定义这个结构体叫:GPIO_InitTypeDef,同时这个结构体里有三个变量,GPIO_Pin,GPIO_Speed,GPIO_Mode。用来初始化单片机的GPIO的三个参数,引脚,模式,速度。
然后再主函数中,调用这个typedef的结构体GPIO_InitTypeDef去创造一个特定的结构体,如下:
1 2 3 4
| GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; GPIO_InitStruct.GPIO_Pin=GPIO_Pin_1;
|
也可通过定义一个指针,指针指向结构体的地址,然后就可以通过这个指针去定义结构体内部的值。
1 2 3 4 5 6 7 8 9 10 11 12 13
| typedef struct{ int a; char b; }GPIO_InitStruct; int main(){ GPIO_InitStruct InitStruct; GPIO_InitStruct *pInitStruct=&InitStruct; pInitStruct->a=10; pInitStruct->b='a'; printf("InitStruct.a=%d\n",InitStruct.a); printf("InitStruct.b=%c\n",InitStruct.b); return 0; }
|
枚举
枚举其实就是用来给一堆整数常量起名字的。
1 2 3 4 5 6 7 8
| enum weekday { SUN,MON,TUE,WED,THU }; int main(){ day=MON; printf("%d\n",day); return 0; }
|
输出的结果是:
1
也可以给枚举类型中的某个元素单独赋值。
*和&在C语言中的作用
*****,当他在定义变量时,他是指指针变量这种变量类型。
而在非定义变量时,他是解指针的意思,就是在一个指针变量前加上*就等于这个指针变量指向地址所存储的真实的值。
**&**,指一个变量的地址,这也包括取指针变量的地址。
取整和取余
取整/
1.强制类型转换
比如,有一个浮点类型的数,2.1。
可以通过把他强制转化为int类型。
1 2
| float num=2.1; int result = (int)num;
|
2.整数除法
取余%
用法1:取余来判断奇偶性
if(a%2==0){}用a除2的余数来判断a是不是偶数,如果结果为0,则a是偶数,否则a为奇数。
用法2:取一个整数的个位数
用a%10可以取出a的个位数,比如123%10=3。
用a%100可以取出a的最后两位数,比如2143%100=43。
if/while
对于有返回值的函数中,写if==必须明确返回值==
1 2 3 4 5 6
| uint8_t Serial_ReceiveByte(void) { if (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == SET) { return USART_ReceiveData(USART1); } }
|
当 if 条件不成立时,程序会走到 if 外面,但函数没写任何返回值,属于未定义行为:
- 编译器会报警告;
- 运行时会返回一个栈上的随机 “垃圾值”,可能让你误以为收到了数据,引发莫名其妙的 bug。
==正确写法==
1 2 3 4 5 6
| uint8_t Serial_ReceiveByte(void){ if(USART_GetFlagStatus(USART1,USART_FLAG_RXNE)==SET){ return USART_ReceiveData(USART1); } return 0; }
|
else if
if / else if / else 互斥,同一时刻只能走其中一个分支。
而多个if的之间相互独立,程序会依次全部判断,满足几个就执行几个,所以可能出现同一时刻满足多个if的情况。
time函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h>
time_t time_cnt; typedef struct tm tm; tm time_data; struct tm time_data;
int main(void){ time(&time_cnt); printf("%ld\n" , time_cnt); time_data =* gmtime(&time_cnt);
time_cnt=mktime(&time_data); printf("Year:%d\n",time_data.tm_year+1900); printf("Month:%d\n",time_data.tm_mon+1); printf("Day:%d\n",time_data.tm_mday); printf("Hour:%d\n",time_data.tm_hour+8); printf("Minute:%d\n",time_data.tm_min); printf("Second:%d\n",time_data.tm_sec); printf("Weekday:%d\n",time_data.tm_wday); return 0; }
|