C/C++在工作中de笔记以及Debug历程
文中有错误的地方,也请指出,我也会进一步改正,大家互相学习,谢谢~
笔记
C/C++中函数指针的定义以及使用:
typedef (返回值类型) (*pFunction)(参数);
- 运用函数指针,建立函数列表,以及调用方式
//定义函数指针
typedef void (*pFunction)(unsigned char *pMsg,unsigned short length);
//定义函数
void Function_01(unsigned char *pMsg,unsigend short length);
void Function_02(unsigned char *pMsg,unsigend short length);
void Function_03(unsigned char *pMsg,unsigend short length);
...
//定义结构体,将函数和索引进行绑定
typedef struct funcList
{
unsigned int index;
pFcuntion pFunc;
}
//定义函数列表
funcList FunctionList[] =
{
{ 0x01 ,&Function_01 }
{ 0x02 ,&Function_02 }
{ 0x03 ,&Function_03 }
...
}
//函数列表中函数数量
unsigned int NumOfFunc = sizeof(FunctionList)/sizeof(FunctionList[0]);
//函数列表的使用
//检索函数索引,匹配对应项
for (int i = 0; i < NumOfFunc; i++)
{
if (index == FunctionList[i].index)
{
//索引配对,this指针指向相应函数,完成调用
(this->*FunctionList[i].pFunc)(pMsg, length);
break;
}
}
STM32的Bootloader的使用
通过使用BootLoader,可以使得同一芯片中,包含多套程序,并实现程序跳转。
//定义APP所在地址
#define AddressOfApplication 0x08002800
void (*AppFunction)(void);
__ASM void MSR_MSP(unsigned int address)
{
MSR MSP, r0
BX r14
};
void JumpToApp(unsigned int address)
{
//先判断地址合法性
if(((*(__IO unsigned int*)address) & 0x2FFE0000) == 0x20000000)
{
//将函数指针指向App的中断向量表
//(address)是App程序的起始地址
//(address + 4)是App的中断向量表的地址
AppFunction = (void(*)())*(__IO unsigned int*)(address + 4);
//此处分割成 (void(*)()) 和 *(__IO unsigned int*)(address + 4)
//这么看会好理解点
MSR_MSP(*(__IO unsigned int*)address);
for(int i = 0;i < 8;i++)
{
//关闭中断
NVIC->ICER[i] = 0xFFFFFFFF;
NVIC->ICPR[i] = 0xFFFFFFFF;
}
//跳转至App的中断向量表
AppFunction();
}
}
程序中的AddressOfApplication的地址值根据实际程序烧写地址来决定
在 Project 菜单中的 Option for Target ‘xxxx’… 选项里的 Target 选项卡里左下方勾选的IROM1的地址决定。
比如我这里的设定是:
default | on-chip | Start | Size | Startup |
---|---|---|---|---|
√ | IROM1: | 0x0800 0000 | 0x0000 2800 | · |
那我的BootLoader的起始地址是0x0800 0000,占用空间是0x0000 2800(10KB),那我的Application的程序在烧写时,地址就设在0x0800 2800开始或者之后,则我的Application在这里填写的值就为:
default | on-chip | Start | Size | Startup |
---|---|---|---|---|
√ | IROM1: | 0x0800 2800 | 0x0002 0000 | · |
BootLoader和Application两套程序烧写完后,运行起来,BootLoader运行完后跳转就会跳到Application继续运行了。
还可以在BootLoader里面对Application的程序进行更新升级,根据外设的不同,可以进行远程升级,OTA升级等等的。
联合体和结构体的搭配使用的妙用
union Example
{
unsigned char someBytes[6];
struct
{
//第一个字节
unsigned char ByteOne_A : 1;
unsigned char ByteOne_B : 2;
unsigned char ByteOne_C : 3;
unsigned char ByteOne_D : 1;
//第二个字节
unsigned char ByteTwo_A : 3;
unsigned char ByteTwo_B : 2;
unsigned char ByteTwo_C : 3;
//第三~六字节
unsigned int Byte3To6;
}detail;
};
首先做一些概念的解释
联合体(union),简单讲就是联合体内的各个成员共用一段内存空间,这段空间的长度有该联合体内使用长度最长的决定。
结构体(struct),由一系列具有相同类型或不同类型的数据构成的数据集合
这里通过两者的嵌套使用以及":"的使用,使得可以精确到位进行操作,例如:
Example temp;
temp.detail.ByteOne_A = 0x01;
temp.detail.ByteTwo_A = 0x03;
temp.detail.ByteTwo_C = 0x02;
temp.detail.Byte3To6 = 0x12345678;
for(int i = 0;i < 6;i++)
{
printf("%X ",temp.someBytes[i]);
}
结果会打印出
80 C2 12 34 56 78
ARM-Linux下App写日志
va_list 是在C语言中解决变参问题的一组宏,用于获取不确定个数的参数。
使用时需包含头文件 stdarg.h
通过使用va可以轻松实现和printf基本一致的功能,但是我们此时要的不是仅仅打印在屏幕上,而是写入到本地日志文件中,建立一套自己的日志文件系统。
#include <iostream>
#include <iomanip>
#include <fstream>
using namespace std;
#include "time.h"
#include "stdarg.h"
void WriteLog(const char *stringData, ...)
{
va_list va;
time_t timeTemp;
struct tm *timer;
char buff[1024];
timeTemp = time(NULL);
timer = localtime(&timeTemp);
ofstream fout;
fout.open("./log/log.txt",ios::app);
va_start(va,stringData);
vsnprintf(buff,1024,stringData,va);
fout << endl;
//写入写日志的时间
fout << timer->tm_year + 1900 << "-" << setw(2) << timer->tm_mon + 1 << "-" << setw(2) << timer->tm_mday << " ";
fout << setw(2) << timer->tm_hour << ":" << setw(2) << timer->tm_min << ":" << setw(2) << timer->sec << " :";
//写日志数据
fout << buff << endl;
fout << "\t\t\t 版本号 : " << "Ver x.x.x" << endl;
va_end;
fout.close();
}
C++检测文件大小
int CheckSizeOfFile(const char *filename)
{
ifstream fin;
fin.open(filename);
if(!fin.is_open())
{
fin.close();
return 0;
}
fin.seekg(0,ios::end);
streampos sp = fin.tellg();
return (int)sp;
}
ARM-Linux多线程以及线程锁
Debug
segment fault
持续更新,敬请期待。。。