嵌入式大佬 | 嵌入式C语言知识点万字总结
扫描二维码
随时随地手机看文章
1 关键字
嵌入式的应用从逻辑上可以抽象为三个部分:
2). 数据的处理(如协议的解码和封包,AD采样值的转换等)
3). 数据的输出(GUI的显示,输出的引脚状态,DA的输出控制电压,PWM波的占空比等),
2 数据类型
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
......
typedef signed int int32_t;
printf( "int size:%d, short size:%d, char size:%d\n", sizeof( int), sizeof( char), sizeof( short));
char *p;
printf( "point p size:%d\n", sizeof(p));
3 内存管理和存储架构
这里先看个简单的C语言实例。
//main.c#include <stdio.h>#include <stdlib.h>
static int st_val; //静态全局变量 -- 静态存储区
int ex_val; //全局变量 -- 静态存储区int main(void)
{
int a = 0; //局部变量 -- 栈上申请
int *ptr = NULL; //指针变量
static int local_st_val = 0; //静态变量
local_st_val += 1;
a = local_st_val;
ptr = ( int *) malloc( sizeof( int)); //从堆上申请空间
if(ptr != NULL)
{
printf( "*p value:%d", *ptr);
free(ptr);
ptr = NULL;
//free后需要将ptr置空,否则会导致后续ptr的校验失效,出现野指针
}
}
LD_ROM 0x00800000 0x10000 { ;load region size_region
EX_ROM 0x00800000 0x10000 { ;load address = execution address
*.o (RESET, +First)
*(InRoot$Sections)
.ANY (+RO)
}
EX_RAM 0x20000000 0xC000 { ;rw Data
.ANY (+RW +ZI)
}
EX_RAM1 0x2000C000 0x2000 {
.ANY(MySection)
}
EX_RAM2 0x40000000 0x20000{
.ANY(Sdram)
}
}
int a[ 10] __attribute__((section( "Mysection")));
int b[ 100] __attribute__((section( "Sdram")));
4 指针和数组
int main(void)
{
char cval[] = "hello";
int i;
int ival[] = { 1, 2, 3, 4};
int arr_val[][ 2] = {{1, 2}, {3, 4}};
const char *pconst = "hello";
char *p;
int *pi;
int *pa;
int **par;
p = cval;
p++; //addr增加1
pi = ival;
pi+= 1; //addr增加4
pa = arr_val[ 0];
pa+= 1; //addr增加4
par = arr_val;
par++; //addr增加8
for(i= 0; i< sizeof(cval); i++)
{
printf( "%d ", cval[i]);
}
printf( "\n");
printf( "pconst:%s\n", pconst);
printf( "addr:%d, %d\n", cval, p);
printf( "addr:%d, %d\n", icval, pi);
printf( "addr:%d, %d\n", arr_val, pa);
printf( "addr:%d, %d\n", arr_val, par);
}
/* PC端64位系统下运行结果
0x68 0x65 0x6c 0x6c 0x6f 0x0
pconst:hello
addr:6421994, 6421995
addr:6421968, 6421972
addr:6421936, 6421940
addr:6421936, 6421944 */
#include <stdio.h>
typedef struct
{
int b;
int a;
}STRUCT_VAL;
static __align( 4) char arr[ 8] = { 0x12, 0x23, 0x34, 0x45, 0x56, 0x12, 0x24, 0x53};
int main(void)
{
STRUCT_VAL *pval;
int *ptr;
pval = (STRUCT_VAL *)arr;
ptr = ( int *)&arr[ 4];
printf( "val:%d, %d", pval->a, pval->b);
printf( "val:%d,", *ptr);
}
//0x45342312 0x53241256
//0x53241256
#include <stdio.h>
typedef int (*pfunc)(int, int);
int func_add(int a, int b){
return a+b;
}
int main(void)
{
pfunc *func_ptr;
*( volatile uint32_t *) 0x20001000 = 0x01a23131;
func_ptr = func_add;
printf( "%d\n", func_ptr( 1, 2));
}
2)一个中断服务子程序中会访问到的非自动变量(Non-automatic variables)
3)多线程应用中被几个任务共享的变量
5 结构类型和对齐
typedef enum {spring= 1, summer, autumn, winter }season;
season s1 = summer;
typedef union{
char c;
short s;
int i;
}UNION_VAL;
UNION_VAL val;
int main(void)
{
printf( "addr:0x%x, 0x%x, 0x%x\n",
( int)(&(val.c)), ( int)(&(val.s)), ( int)(&(val.i)));
val.i = 0x12345678;
if(val.s == 0x5678)
printf( "小端模式\n");
else
printf( "大端模式\n");
}
/*
addr:0x407970, 0x407970, 0x407970
小端模式
*/
int data = 0x12345678;
short *pdata = ( short *)&data;
if(*pdata = 0x5678)
printf( "%s\n", "小端模式");
else
printf( "%s\n", "大端模式");
typedef int (*pfunc)(int, int);
typedef struct{
int num;
int profit;
pfunc get_total;
}STRUCT_VAL;
int GetTotalProfit(int a, int b)
{
return a*b;
}
int main(void){
STRUCT_VAL Val;
STRUCT_VAL *pVal;
Val.get_total = GetTotalProfit;
Val.num = 1;
Val.profit = 10;
printf( "Total:%d\n", Val.get_total(Val.num, Val.profit)); //变量访问
pVal = &Val;
printf( "Total:%d\n", pVal->get_total(pVal->num, pVal->profit)); //指针访问
}
/*
Total:10
Total:10
*/
typedef unsigned char uint8_t;
union reg{
struct{
uint8_t bit0: 1;
uint8_t bit1: 1;
uint8_t bit2_6: 5;
uint8_t bit7: 1;
}bit;
uint8_t all;
};
int main(void)
{
union reg RegData;
RegData.all = 0;
RegData.bit.bit0 = 1;
RegData.bit.bit7 = 1;
printf( "0x%x\n", RegData.all);
RegData.bit.bit2_6 = 0x3;
printf( "0x%x\n", RegData.all);
}
/*
0x81
0x8d
*/
数组 :按照基本数据类型对齐,第一个对齐了后面的自然也就对齐了。
联合体 :按其包含的长度最大的数据类型对齐。
结构体:结构体中每个数据类型都要对齐,结构体本身以内部最大数据类型长度对齐
union DATA{
int a;
char b;
};
struct BUFFER0{
union DATA data;
char a;
//reserved[3]
int b;
short s;
//reserved[2]
}; //16字节
struct BUFFER1{
char a;
//reserved[0]
short s;
union DATA data;
int b;
}; //12字节
int main(void)
{
struct BUFFER0 buf0;
struct BUFFER1 buf1;
printf( "size:%d, %d\n", sizeof(buf0), sizeof(buf1));
printf( "addr:0x%x, 0x%x, 0x%x, 0x%x\n",
( int)&(buf0.data), ( int)&(buf0.a), ( int)&(buf0.b), ( int)&(buf0.s));
printf( "addr:0x%x, 0x%x, 0x%x, 0x%x\n",
( int)&(buf1.a), ( int)&(buf1.s), ( int)&(buf1.data), ( int)&(buf1.b));
}
/*
size:16, 12
addr:0x61fe10, 0x61fe14, 0x61fe18, 0x61fe1c
addr:0x61fe04, 0x61fe06, 0x61fe08, 0x61fe0c
*/
6 预处理机制
include 包含文件命令,在C语言中,它执行的效果是将包含文件中的所有内容插入到当前位置,这不只包含头文件,一些参数文件,配置文件,也可以使用该文件插入到当前代码的指定位置。其中<>和""分别表示从标准库路径还是用户自定义路径开始检索。
define宏定义,常见的用法包含定义常量或者代码段别名,当然某些情况下配合##格式化字符串,可以实现接口的统一化处理,实例如下:
#define MAX_SIZE 10
#define MODULE_ON 1
#define ERROR_LOOP() do{\
printf("error loop\n");\
}while(0);
#define global(val) g_##val
int global(v) = 10;
int global(add)(int a, int b)
{
return a+b;
}
if..#elif…#else…#endif, #ifdef..#endif, #ifndef…#endif条件选择判断,条件选择主要用于切换代码块,这种综合性项目和跨平台项目中为了满足多种情况下的需求往往会被使用。
undef 取消定义的参数,避免重定义问题。
error,#warning用于用户自定义的告警信息,配合#if,#ifdef使用,可以限制错误的预定义配置。
pragma 带参数的预定义处理,常见的#pragma pack(1), 不过使用后会导致后续的整个文件都以设置的字节对齐,配合push和pop可以解决这种问题,代码如下:
#pragma pack(push)
#pragma pack(1)
struct TestA
{
char i;
int b;
}A;
#pragma pack(pop); //注意要调用pop,否则会导致后续文件都以pack定义值对齐,执行不符合预期
等同于
struct _TestB{
char i;
int b;
}__attribute__((packed))A;
总结
猜你喜欢(点击下划线即可跳转阅读
嵌入式牛人 | 这些单片机编程思想超硬核
嵌入式必会!C语言最常用的贪心算法就这么被攻略了
Linux!为何他一人就写出这么强的系统?
最 后
免责声明:本文内容由21ic获得授权后发布,版权归原作者所有,本平台仅提供信息存储服务。文章仅代表作者个人观点,不代表本平台立场,如有问题,请联系我们,谢谢!