69.自己实现printf,并且能提示警告,需要使用format
int __attribute__((format(printf, 4, 5))) logcFunc(int lev, const char *lfile, int lline, const char *fmt, ...);
4表示格式字符串位置-fmt,5表示可变变量的起始位置
int __attribute__((format(printf, 4, 5))) logcFunc(int lev, const char *lfile, int lline, const char *fmt, ...);
int logcFunc(int lev, const char *lfile, int lline, const char *fmt, ...)
{
if (lev > logLevelParam)
{
return 0;
}
static const char *logstr[] = {
"fat",
"err",
"wrn",
"inf",
"dbg",
"trc"};
struct timeval tnow;
struct tm *tmnow;
gettimeofday(&tnow, NULL);
tmnow = localtime(&tnow.tv_sec);
char tmpPrtStr[2048] = {0};
const char *tmpFileName;
(tmpFileName = strrchr(lfile, '/')) ? tmpFileName++ : (tmpFileName = lfile);
int tmplen = snprintf(tmpPrtStr, sizeof(tmpPrtStr), "[%d-%02d-%02d %02d:%02d:%02d.%03d]%s[%s,%d]",
tmnow->tm_year + 1900, tmnow->tm_mon + 1, tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec,
(int)tnow.tv_usec / 1000 % 1000, logstr[lev], tmpFileName, lline);
va_list args;
va_start(args, fmt);
tmplen += vsnprintf(tmpPrtStr + tmplen, sizeof(tmpPrtStr) - tmplen, fmt, args);
va_end(args);
printf("%s\n", tmpPrtStr);
return tmplen;
}
68.协议参考
控制器六联按钮、语音、锁板的485协议。(波特率57600,数据位8,校验位'n',停止位1)(此协议12字节包头) | ||
名称 | 长度(字节) | 说明 |
包头 | 3 | 0xa5,0x6c,0x93。防冲突 |
版本号 | 1 | 0单片机协议 |
数据长度 | 2 | 小端,10长度表示0x0a,0x00。是数据区的长度。4+N |
加密类型 | 1 | 0无,1DES,其他 |
包校验 | 1 | 求和 |
数据区 | 参考下面 | |
命令 | 2 | 小端,10表示0x0a,0x00。命令应答需一致。 |
序列号 | 1 | 小端,10表示0x0a,0x00。命令应答需一致。 |
485地址 | 1 | 0-254表示地址,255表示广播 |
数据内容 | N | 根据不同命令自定义 |
控制器六联按钮、语音、锁板的485协议。(波特率57600,数据位8,校验位'n',停止位1)(此协议20字节包头) | ||
名称 | 长度(字节) | 说明 |
包头 | 3 | 0xa5,0x6c,0x93。防冲突 |
版本号 | 1 | 1增强版 |
数据长度 | 4 | 小端,10长度表示0x0a,0x00,0x00,0x00。是数据区的长度。8+N |
加密类型 | 1 | 0无,1DES,其他 |
保留/压缩 | 1 | 1:压缩 |
数据类型 | 1 | 0:结构体格式,1:json格式 |
包校验 | 1 | 求和 |
数据区 | 参考下面 | |
命令 | 2 | 小端,10表示0x0a,0x00。命令应答需一致。 |
序列号 | 2 | 小端,10表示0x0a,0x00。命令应答需一致。 |
485地址 | 1 | 0-254表示地址,255表示广播 |
设备类型 | 1 | 1锁板,2六联按钮,3语音模块 |
应答 | 1 | 0执行成功,其他表示特殊或错误代码 |
保留 | 1 | 无 |
数据内容 | N | 根据不同命令自定义 |
67.画流程图工具:
processOn
66.数据数组与enum对应需要修改两个地方修正:
#########################################################
连接头文件:idmap.h
ID_COMMAND_DEFINE_FUNC(myIdCommand_help, funcIdCommand_help, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_exit,funcIdCommand_exit, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_quit, funcIdCommand_quit, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_printCmd, funcIdCommand_printCmd, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_add, funcIdCommand_add, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_del, funcIdCommand_del, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_multi, funcIdCommand_multi, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_div, funcIdCommand_div, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_myname, funcIdCommand_myname, NULL),
ID_COMMAND_DEFINE_FUNC(myIdCommand_maxIndex, NULL, NULL)
#########################################################
应用头文件:func.h
#include <time.h>
#include <unistd.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#define DEBUG_LEVEL_DEF 5
#define PRINTF_DEF(lev, fmt, lprt, ...) \
do \
{ \
if (DEBUG_LEVEL_DEF >= lev) \
{ \
struct timeb tnow; \
struct tm *tmnow; \
ftime(&tnow); \
tmnow = localtime(&tnow.time); \
printf("[%d-%02d-%02d %02d:%02d:%02d.%03d][%s][%s,%d]" fmt "\n", tmnow->tm_year + 1900, tmnow->tm_mon + 1, \
tmnow->tm_mday, tmnow->tm_hour, tmnow->tm_min, tmnow->tm_sec, tnow.millitm % 1000, \
lprt, __func__, __LINE__, ##__VA_ARGS__); \
} \
} while (0);
#define logwfat(fmt, ...) PRINTF_DEF(0, fmt, "fat", ##__VA_ARGS__)
#define logwerr(fmt, ...) PRINTF_DEF(1, fmt, "err", ##__VA_ARGS__)
#define logwwarn(fmt, ...) PRINTF_DEF(2, fmt, "war", ##__VA_ARGS__)
#define logwinfo(fmt, ...) PRINTF_DEF(3, fmt, "inf", ##__VA_ARGS__)
#define logwdbg(fmt, ...) PRINTF_DEF(4, fmt, "dbg", ##__VA_ARGS__)
#define logwtra(fmt, ...) PRINTF_DEF(5, fmt, "tra", ##__VA_ARGS__)
enum myenum
{
#undef ID_COMMAND_DEFINE_FUNC
#define ID_COMMAND_DEFINE_FUNC(ENUMNUMBER, ...) ENUMNUMBER
#include <idmap.h>
#undef ID_COMMAND_DEFINE_FUNC
};
#pragma pack(1)
#define SLAVE_DEVICE_FLOORS_NUMBER 16
#define SLAVE_COMMAND_DATA_MAX_LEN 1024
struct commandUpgradeSlaveProgram
{
uint32_t offset;
uint8_t data[SLAVE_COMMAND_DATA_MAX_LEN];
};
struct commandUpgradeSlaveFinish
{
uint32_t totalLen;
uint32_t fileCrc;
};
struct commandControlFloorRelay
{
uint16_t driverRelayA_Time;
uint16_t driverRelayB_Time;
uint8_t switchA[SLAVE_DEVICE_FLOORS_NUMBER];//0:close, 1:open
uint8_t switchB[SLAVE_DEVICE_FLOORS_NUMBER];//0:close, 1:open
};
struct commandForceCtrlFloors
{
//0:normal, 1:allways close, 2:allways open
uint8_t controlData[SLAVE_DEVICE_FLOORS_NUMBER];
};
struct commandControlSetAddr485
{
uint8_t addr;
};
struct commandControlSetAddrByUid
{
uint8_t uid[12];
uint8_t addr;
};
//response list
struct responseHeartNormal
{
char slaveVersion[32];
uint8_t slaveUid[12];
};
struct calcDataStruct
{
int val1;
int val2;
};
union slaveCommandOrResponse
{
//cmd
struct commandUpgradeSlaveProgram upProgram;
struct commandUpgradeSlaveFinish upFinish;
struct commandControlFloorRelay floorCtrl;
struct commandForceCtrlFloors forceCtrl;
struct commandControlSetAddr485 addr;
struct commandControlSetAddrByUid set485ByUid;
struct calcDataStruct calcval;
//response
struct responseHeartNormal respHeartNormal;
};
struct slaveCommandCommonStruct
{
uint16_t serialNumber;//序列号
uint16_t retain;//保留
uint16_t devType;//设备类型
uint16_t command;//命令
uint16_t subCmd;//not use
uint8_t addr485;//地址
uint8_t responseFlag;//应答值。
};
struct floorSlaveProtocolDataStruct
{
struct slaveCommandCommonStruct head;
union slaveCommandOrResponse body;
};
#pragma pack()
typedef void (*callbackFunction)(void *data, int len, void *userdata);
struct mystruct
{
callbackFunction cbkfunc;
void *userdata;
};
#########################################################
应用c文件:func.c
#include <func.h>
void funcIdCommand_help(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_exit(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_quit(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_printCmd(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_add(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_del(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_multi(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_div(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
void funcIdCommand_myname(void *data, int len, void *userdata)
{
struct floorSlaveProtocolDataStruct *tmpdata = (struct floorSlaveProtocolDataStruct *)data;
if(!tmpdata)
{
logwerr("");
return;
}
logwdbg("%d, %d, %d", tmpdata->head.command, tmpdata->body.calcval.val1, tmpdata->body.calcval.val2);
}
struct mystruct tmyd[] =
{
#undef ID_COMMAND_DEFINE_FUNC
#define ID_COMMAND_DEFINE_FUNC(ENUMNUMBER, func, udata) {func, udata}
#include <idmap.h>
#undef ID_COMMAND_DEFINE_FUNC
};
int main()
{
logwdbg("");
struct floorSlaveProtocolDataStruct tmpdata;
srand(time(NULL));
for(int i = 0; i < myIdCommand_maxIndex; i++)
{
tmpdata.head.command = i;
tmpdata.body.calcval.val1 = i;
tmpdata.body.calcval.val2 = i + 1;
if(tmyd[i].cbkfunc)
{
tmyd[i].cbkfunc(&tmpdata, sizeof(tmpdata), tmyd[i].userdata);
}
}
while(1)
{
int tmpcmd = rand() % (myIdCommand_maxIndex + 5);
if(tmpcmd >= myIdCommand_maxIndex)
{
logwwarn("cmd over:%d", tmpcmd);
}
else
{
tmpdata.head.command = tmpcmd;
tmpdata.body.calcval.val1 = tmpcmd;
tmpdata.body.calcval.val2 = tmpcmd + 1;
if(tmyd[tmpcmd].cbkfunc)
{
tmyd[tmpcmd].cbkfunc(&tmpdata, sizeof(tmpdata), tmyd[tmpcmd].userdata);
}
}
sleep(1);
}
}
65.do{}while(0);与goto。很多时候函数中需要释放分配空间,释放锁,关闭文件描述符。
#include <stdio.h>
#include <pthread.h>
void function()
{
char *tmpdata = (char *)malloc(10);
if(!tmpdata)
{
//err
return;
}
FILE *tmpFd = fopen("/tmp/xx.txt", "rw");
if(!tmpFd)
{
//err
return;
}
pthread_mutex_t tmplock;
pthread_mutex_init(&tmplock, NULL);
pthread_mutex_lock(&tmplock);
do
{
char tmpread[12] = {0};
fread(tmpread, 1, 10, tmpFd);
if(tmpread[0] = 0)
{
//do1
break;
}
else if(tmpread[0] = 1)
{
//do2
break;
}
//do3
}while (0);
if(tmpdata)
{
free(tmpdata);
tmpdata = NULL;
}
if(tmpFd)
{
//err
fclose(tmpFd);
return;
}
pthread_mutex_unlock(&tmplock);
pthread_mutex_destroy(&tmplock);
}
void function()
{
char *tmpdata = (char *)malloc(10);
if(!tmpdata)
{
//err
return;
}
FILE *tmpFd = fopen("/tmp/xx.txt", "rw");
if(!tmpFd)
{
//err
return;
}
pthread_mutex_t tmplock;
pthread_mutex_init(&tmplock, NULL);
pthread_mutex_lock(&tmplock);
char tmpread[12] = {0};
fread(tmpread, 1, 10, tmpFd);
if(tmpread[0] = 0)
{
//do1
goto finishPointor;
}
else if(tmpread[0] = 1)
{
//do2
goto finishPointor;
}
//do3
finishPointor:
if(tmpdata)
{
free(tmpdata);
tmpdata = NULL;
}
if(tmpFd)
{
//err
fclose(tmpFd);
return;
}
pthread_mutex_unlock(&tmplock);
pthread_mutex_destroy(&tmplock);
}
64.程序配置时区
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <iostream>
#include <fstream>
#include <sys/time.h>
#include <unistd.h>
class timezoneOperateClass
{
#define TIMEZONE_DEFUALT_VALUE -8
#define TIMEZONE_SAVE_PATH_FILE "/mnt/data/codeTimeZone.txt"
public:
timezoneOperateClass(std::string setTzFile = TIMEZONE_SAVE_PATH_FILE)
{
timezone = TIMEZONE_DEFUALT_VALUE;
tzSaveFile = setTzFile;
configTimezone();
time_t td;
time(&td);
printf("[%s,%d], date = %s\n", __FILE__, __LINE__, asctime(localtime(&td)));
}
timezoneOperateClass()
{
}
static std::string readFileAll(const char *pathwrd, int readMaxLen = 1024)
{
std::ifstream tmpif;
int filelen;
tmpif.open(pathwrd, std::ios::in | std::ios::binary);
if (!tmpif.is_open())
{
printf("err:%s\n", pathwrd);
return "";
}
tmpif.seekg(0, std::_S_end);
filelen = tmpif.tellg();
if (filelen < readMaxLen)
{
std::string outstr(filelen, 0);
tmpif.seekg(0);
tmpif.read(&outstr[0], filelen);
return outstr;
}
else
{
printf("file too big:%s\n", pathwrd);
return "";
}
}
static int writeFileStr(const char *filepath, std::string writestr)
{
std::ofstream outfs;
outfs.open(filepath, std::ios::out);
if (!outfs.is_open())
{
printf("err:%s\n", filepath);
return -1;
}
outfs.write(writestr.c_str(), writestr.length());
outfs.flush();
return 0;
}
static void setTimezone(int setzone)
{
char tmpbuf[128];
if(setzone > 12)
{
setzone = 12;
}
else if(setzone < -12)
{
setzone = -12;
}
if(setzone >= 0)
{
snprintf(tmpbuf, sizeof(tmpbuf), "TZ=UTC+%d", setzone);
}
else
{
snprintf(tmpbuf, sizeof(tmpbuf), "TZ=UTC%d", setzone);
}
printf("[%s,%d]set string :%s\n", __FILE__, __LINE__, tmpbuf);
putenv(tmpbuf);
tzset();
}
static timezoneOperateClass &instance()
{
static timezoneOperateClass tzwork(TIMEZONE_SAVE_PATH_FILE);
return tzwork;
}
void configTimezone(int setzone = 1000)
{
std::string readZoneData = "";
char tmpbuf[128];
if(setzone >= -12 && setzone <= 12)
{
timezone = setzone;
}
else
{
readZoneData = readFileAll(tzSaveFile.c_str(), 30);
}
if(readZoneData == "")
{
// printf("[%s,%d], %d\n", __FILE__, __LINE__, timezone);
snprintf(tmpbuf, sizeof(tmpbuf), "%d", timezone);
writeFileStr(tzSaveFile.c_str(), tmpbuf);
}
else
{
timezone = atoi(readZoneData.c_str());
if(timezone > 12)
{
timezone = 12;
}
else if(timezone < -12)
{
timezone = -12;
}
}
printf("[%s,%d], %d, timezone=%d, readData=%s\n", __FILE__, __LINE__, setzone, timezone, readZoneData.c_str());
setTimezone(timezone);
}
int getTimezoneValue()
{
return timezone;
}
private:
int timezone;
std::string tzSaveFile;
};
void testSetTimezone(int setzone)
{
timezoneOperateClass::instance().configTimezone(setzone);
// timezoneOperateClass::instance().getTimezoneValue();
time_t td;
time(&td);
// timeval tmptv;
// gettimeofday(&tmptv, NULL);
// printf("[%s,%d], %u, %u\n", __FILE__, __LINE__, td, tmptv.tv_sec);
printf("[%s,%d], date = %s\n", __FILE__, __LINE__, asctime(localtime(&td)));
}
int main(void)
{
// timezoneOperateClass::instance();
// testSetTimezone(0);
// testSetTimezone(-8);
testSetTimezone(1000);
testSetTimezone(-11);
testSetTimezone(11);
testSetTimezone(-1);
testSetTimezone(1);
testSetTimezone(-12);
testSetTimezone(12);
testSetTimezone(0);
testSetTimezone(-8);
testSetTimezone(1000);
return 0;
}
63.一份简单的协议:
备注一下:#pragma pack (1)如果里面有std::string,可能导致std::string使用异常!
#ifndef __USER_PROTOCOL_V1_H__
#define __USER_PROTOCOL_V1_H__
#include <types.h>
#include <logBaseWork.h>
#include <ctimer.h>
//protocol
#define COMPRTC_PACK_MAX_LEN (1100)
#define COMPRTC_FIX_HEAD_LEN (3)
enum COMPRTC_VERSION_ENUM
{
COMPRTC_VERSION_V0 = 0,
COMPRTC_VERSION_V1,//JSON
COMPRTC_VERSION_V2,//
};
enum COMPRTC_PARSE_STEP_ENUM
{
COMPRTC_PARSE_FIXED_HEAD = 0,
COMPRTC_PARSE_GET_VER,
COMPRTC_PARSE_GET_HEAD,
COMPRTC_PARSE_GET_DATA,
COMPRTC_PARSE_STEP_MAX,
};
typedef void(*comPrtcUsrCbk)(void *udata, u8 *data, u32 len);
#pragma pack (1)
struct comPrtcV0Head
{
u8 fixedHead[COMPRTC_FIX_HEAD_LEN];//固定0XC6B796
u8 protocVer;//协议版本
u8 encodeType;//加密类型
u8 compressType;//压缩标志
u16 crc;//求和校验
u32 datalen;//数据长度
};
#pragma pack()
#define COMPRTCV0_HEAD_TOTAL_LEN (sizeof(struct comPrtcV0Head))
#define COMPRTCV0_DATA_MAX_LEN (COMPRTC_PACK_MAX_LEN - COMPRTCV0_HEAD_TOTAL_LEN)
#define PROJECT_PROTOC_USE_VER COMPRTC_VERSION_V0
struct comPrtcParseStruct
{
u32 stepval;
u32 datalen;
union
{
struct comPrtcV0Head pV0Head;
u8 pheadData[64];
};
std::string dbuf;
u16 pheadLen;//包头长度
u8 prtclStep;
u8 pver;//包头版本
comPrtcUsrCbk doCmd;
void *usrData;
};
class comProtocClass
{
public:
comProtocClass()
{
pcwork.doCmd = NULL;
pcwork.usrData = NULL;
}
~comProtocClass()
{
}
void initUsrInf(comPrtcUsrCbk cbk, void *udata)
{
pcwork.doCmd = cbk;
pcwork.usrData = udata;
prctlFixHead[0] = 0xc6;
prctlFixHead[1] = 0xb7;
prctlFixHead[2] = 0x96;
parseInit();
}
static u16 calc16Crc(const u8 *bdat, u32 blen)
{
u32 i = 0;
u16 crc = 0;
for(i = 0; i < blen; i++)
{
crc += bdat[i];
}
return crc;
}
static u32 packProtDataV0(std::string &packData, const u8 *data, u32 dlen, u8 encFlag, u8 cprss)
{
struct comPrtcV0Head tmphead;
u16 tmpcrc;
const u8 tmpFixHead[COMPRTC_FIX_HEAD_LEN] = {0xc6, 0xb7, 0x96};
if(!(dlen > 0 && dlen <= COMPRTCV0_DATA_MAX_LEN))
{
logwdbg("%d", dlen);
return 0;
}
tmpcrc = calc16Crc(data, dlen);
memset(&tmphead, 0, sizeof(tmphead));
memcpy(tmphead.fixedHead, tmpFixHead, COMPRTC_FIX_HEAD_LEN);
tmphead.protocVer = COMPRTC_VERSION_V0;
tmphead.encodeType = 0;
tmphead.compressType = 0;
tmphead.crc = tmpcrc;
tmphead.datalen = dlen;
packData.resize(COMPRTCV0_HEAD_TOTAL_LEN + dlen);
memcpy(&packData[0], &tmphead, COMPRTCV0_HEAD_TOTAL_LEN);
memcpy((char *)(&packData[0]) + COMPRTCV0_HEAD_TOTAL_LEN, data, dlen);
return COMPRTCV0_HEAD_TOTAL_LEN + dlen;
}
static u32 packProtocData(std::string &packData, const u8 *data, u32 dlen, u8 encFlag, u8 cprss)
{
if(COMPRTC_VERSION_V0 == PROJECT_PROTOC_USE_VER)
{
return packProtDataV0(packData, data, dlen, encFlag, cprss);
}
else
{
logwwrn("version is not surport:%d", PROJECT_PROTOC_USE_VER);
return 0;
}
}
void parseInit()
{
pcwork.prtclStep = COMPRTC_PARSE_FIXED_HEAD;
pcwork.stepval = 0;
pcwork.dbuf.clear();
}
void parseFunc(u8 indata)
{
u16 tmpcrc = 0;
switch (pcwork.prtclStep)
{
case COMPRTC_PARSE_FIXED_HEAD:
{
if(pcwork.stepval < COMPRTC_FIX_HEAD_LEN)
{
if(indata == prctlFixHead[pcwork.stepval])
{
pcwork.pheadData[pcwork.stepval++] = indata;
}
else
{
pcwork.stepval = 0;
if(indata == prctlFixHead[pcwork.stepval])
{
pcwork.pheadData[pcwork.stepval++] = indata;
}
}
}
if(pcwork.stepval >= COMPRTC_FIX_HEAD_LEN)
{
pcwork.prtclStep = COMPRTC_PARSE_GET_VER;
}
break;
}
case COMPRTC_PARSE_GET_VER:
{
if(indata != PROJECT_PROTOC_USE_VER)
{
logwwrn("version is not surport:%d", indata);
parseInit();
break;
}
if(indata == COMPRTC_VERSION_V0)
{
pcwork.pver = COMPRTC_VERSION_V0;
pcwork.pheadLen = COMPRTCV0_HEAD_TOTAL_LEN;
}
else
{
logwwrn("version is not surport:%d", indata);
parseInit();
break;
}
if(pcwork.pheadLen > sizeof(pcwork.pheadData))
{
logwwrn("version head is big:%d, %d", indata, pcwork.pheadLen);
parseInit();
break;
}
pcwork.pheadData[pcwork.stepval++] = indata;
pcwork.prtclStep = COMPRTC_PARSE_GET_HEAD;
break;
}
case COMPRTC_PARSE_GET_HEAD:
{
if(pcwork.stepval < pcwork.pheadLen)
{
pcwork.pheadData[pcwork.stepval++] = indata;
}
if(pcwork.stepval >= pcwork.pheadLen)
{
if(pcwork.pver == COMPRTC_VERSION_V0)
{
pcwork.datalen = pcwork.pV0Head.datalen;
}
else
{
logwwrn("version is not surport:%d", pcwork.pver);
parseInit();
break;
}
if((pcwork.datalen > 0) && (pcwork.datalen <= (COMPRTCV0_DATA_MAX_LEN)))
{
pcwork.prtclStep = COMPRTC_PARSE_GET_DATA;
pcwork.dbuf.resize(pcwork.datalen);
pcwork.stepval = 0;
}
else
{
logwdbg("%s", miscOptClass::hexbufToString((const char *)pcwork.pheadData, COMPRTCV0_HEAD_TOTAL_LEN).c_str());
logwwrn("data len is big:%d,%d", pcwork.datalen, pcwork.pV0Head.datalen);
parseInit();
}
}
break;
}
case COMPRTC_PARSE_GET_DATA:
{
if(pcwork.stepval < pcwork.datalen)
{
pcwork.dbuf[pcwork.stepval++] = indata;
}
if(pcwork.stepval >= pcwork.datalen)
{
tmpcrc = calc16Crc((const u8 *)pcwork.dbuf.c_str(), pcwork.datalen);
u16 tmpPackCrc;
u8 encflag;
u8 cprFlag;
//std::string tmpstr;
if(pcwork.pver == COMPRTC_VERSION_V0)
{
tmpPackCrc = pcwork.pV0Head.crc;
encflag = pcwork.pV0Head.encodeType;
cprFlag = pcwork.pV0Head.compressType;
}
else
{
logwwrn("version is not surport:%d", pcwork.pver);
parseInit();
break;
}
if(tmpcrc == tmpPackCrc)
{
if(encflag == 1)
{
}
if(cprFlag == 1)
{
}
// logwdbg("%s", miscOptClass::hexbufToString(pcwork.dbuf.c_str(), pcwork.dbuf.length()).substr(30).c_str());
//tmpstr = pcwork.dbuf;
if(pcwork.doCmd)
{
pcwork.doCmd(pcwork.usrData, (u8 *)pcwork.dbuf.c_str(), pcwork.datalen);
}
}
else
{
logwdbg("%d, %d", tmpcrc, tmpPackCrc);
}
parseInit();
}
break;
}
default:
{
parseInit();
break;
}
}
}
private:
struct comPrtcParseStruct pcwork;
u8 prctlFixHead[COMPRTC_FIX_HEAD_LEN];
};
enum SUBCTRL_CMD_ENUM
{
SUBCTRL_REG_SERVER = 0,
SUBCTRL_REG_HEART,
SUBCTRL_REG_UPGRADE,
SUBCTRL_REG_UPCARD,
SUBCTRL_REG_UPPARM,
SUBCTRL_REG_SCANDEV,
};
struct devProtocCmdStruct
{//单片机命令头
u16 serialNumber;//序列号
u16 retain;//保留
u16 devType;//设备类型
u16 command;//命令
u16 subCmd;//从命令
u8 addr485;//地址
u8 responseFlag;//应答值。
};
#define DEVPRTC_CMD_HEAD_LEN (sizeof(struct devProtocCmdStruct))
class subDevComClass
{
public:
static u32 packSubPrtcBuf(std::string &outdata, const u8 *data, u32 len, struct devProtocCmdStruct &cmdHead)
{
std::string tmpstr;
if(len > COMPRTCV0_DATA_MAX_LEN - DEVPRTC_CMD_HEAD_LEN)
{
logwerr("%d", len);
return 0;
}
tmpstr.resize(len + DEVPRTC_CMD_HEAD_LEN);
memcpy(&tmpstr[0], &cmdHead, DEVPRTC_CMD_HEAD_LEN);
memcpy((&tmpstr[0]) + DEVPRTC_CMD_HEAD_LEN, data, len);
return comProtocClass::packProtocData(outdata, (const u8 *)tmpstr.c_str(), tmpstr.length(), 0, 0);
}
};
#endif
62.undefined reference to错误。就是在ld链接生成执行文件时,没有找到函数。可能原因:
函数的c文件没有包含进来;需要连接.so或.a库;g++包含了gcc编译的c文件
61.自定义简单加密:重复数据也能得到不同的结果。tmpdec为随机数,同包一起发送。
outbuf[i] = ((outbuf[i] - (u8)0x19) ^ tmpenc) + (u8)0x37;
tmpenc += 23;
以及解密:
outbuf[i] = ((inbuf[3 + i] - (u8)0x37) ^ tmpdec) + (u8)0x19;
tmpdec += 23;
#define XOR_PACK_MAX_LEN 6
char getRandChar()
{
return (char)timerc::getTimeNowUs();
//在单片机中可以使用
}
//outbuf len = inbuf len + 5!
//blen is inbuf len
int xorPack(const u8 *inbuf, u8 *outbuf, int inlen)
{
int i = 0;
if(!inbuf || !outbuf)
{
return -1;
}
outbuf[0] = 0x7A;
outbuf[1] = 0XC5;
outbuf[2] = getRandChar();
u8 tmpenc = outbuf[2];
memcpy(outbuf + 3, inbuf, inlen);
outbuf[3 + inlen] = '\r';
outbuf[4 + inlen] = '\n';
// logwdbg("%02x", tmpenc);
for(i = 3; i < inlen + 5; i++)
{
outbuf[i] = ((outbuf[i] - (u8)0x19) ^ tmpenc) + (u8)0x37;
tmpenc += 23;
// outbuf[i] = (outbuf[i] - (u8)0x12) ^ outbuf[2];
}
return 0;
}
//outbuf len = inbuf len - 3!
int xorParse(const u8 *inbuf, u8 *outbuf, int inlen)
{
u8 tmpdec;
int parseOkFlag = 0;// = outbuf[2];
int i = 0;
if(inlen < 5 || !inbuf || !outbuf)
{
logwerr("");
return -1;
}
if(inbuf[0] != 0x7A || inbuf[1] != 0XC5)
{
logwerr("%02x,%02x", inbuf[0], inbuf[1]);
return -2;
}
tmpdec = inbuf[2];
logwdbg("%02x", tmpdec);
for(i = 0; i < inlen - 3; i++)
{
outbuf[i] = ((inbuf[3 + i] - (u8)0x37) ^ tmpdec) + (u8)0x19;
tmpdec += 23;
// outbuf[i] = (inbuf[3 + i] ^ inbuf[2])+ (u8)0x12;
// logwdbg("%02x,%02x", inbuf[3 + i], outbuf[i]);
if(i > 0 && outbuf[i] == '\n' && outbuf[i - 1] == '\r')
{
parseOkFlag = 1;
break;
}
}
if(parseOkFlag)
{
return 0;
}
else
{
logwdbg("");
return -3;
}
}
#define testbuflen 6
int main()
{
// workBaseLog4cplus = log4cplusWorkClassDef("./mybuflog.properties");
char inbuf[testbuflen];
char encbuf[sizeof(inbuf) + 5];
char decbuf[sizeof(inbuf) + 5];
u8 tmpx = (u8)0x12 + (u8)0xf1;
logwdbg("%x", tmpx);
for(long i = 0; i < (long)sizeof(inbuf); i++)
{
inbuf[i] = 0;
}
logwdbg("%s", convertHexStringClass::hexbufToString(inbuf, sizeof(inbuf)).c_str());
xorPack((const u8 *)inbuf, (u8 *)encbuf, sizeof(inbuf));
logwdbg("%s", convertHexStringClass::hexbufToString(encbuf, sizeof(encbuf)).c_str());
xorParse((const u8 *)encbuf, (u8 *)decbuf, sizeof(encbuf));
logwdbg("%s", convertHexStringClass::hexbufToString(decbuf, sizeof(inbuf)).c_str());
return -1;
}
60. ./tcpdump -qA host 192.168.6.168
date +"%Y-%m-%d %H:%M:%S"
59.设置时间问题:settimeofday配置当前时间,不能配置时区,不能设置硬件时钟。
a.配置时区,最好在系统启动时配置:export TZ=CST-8或在/etc/localtime配置时区。如果在程序配置,程序的时间对了,但使用date命令时间还是不对!
// putenv("TZ=EST8EDT");
// setenv("TZ", "CST-8", 1);
// tzset();
b.使用了settimeofday配置时间后,再使用shell:hwclock -w -u -f /dev/rtc中。这样启动后时间也是对的
备注:hwclock -w 同步到时钟芯片, -u用UTC时间同步,-l用当前时间同步,并且-l是默认的!这里需要特别注意
49.localtime和printf第一次使用时系统会分配少量的空间,但不用释放!
48.我们用telnet打开linux终端,linux启动运行的程序打印是在:/dev/console。如果我们想直接把打开的telnet作为console输出参考:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int tty = -1;
char *tty_name = NULL;
if(argc < 2)
{
printf("miss argument\n");
return 0;
}
/* 获取当前tty名称 */
tty_name = ttyname(STDOUT_FILENO);
printf("tty_name: %s\n", tty_name);
if(!strcmp(argv[1], "on"))
{
/* 重定向console到当前tty */
tty = open(tty_name, O_RDONLY | O_WRONLY);
ioctl(tty, TIOCCONS);
perror("ioctl TIOCCONS");
}
else if(!strcmp(argv[1], "off"))
{
/* 恢复console */
tty = open("/dev/console", O_RDONLY | O_WRONLY);
ioctl(tty, TIOCCONS);
perror("ioctl TIOCCONS");
}
else
{
printf("error argument\n");
return 0;
}
close(tty);
return 0;
}
47.printf("%02x", 0xff);输出0xffffffff,可以强制转换再打印:printf("%02x", (unsigned char)0xff);
46.特殊用法:#define getval(a) (a = a+1,a) 使用int d=2; d=getval(d);
45.nandflash理解:有概率坏块,现象来看bootload和kernel不容易出现,应该是经常写的块容易出问题。将/tmp和经常操作的的方进行分区,让/根文件系统能正常启动,程序需要有检测功能,看分区是否坏掉!
44.通讯协议定义个人理解:
包1:
包头2字节;2字节长度;扩展字节,通过参数控制长度(可保存加密类型,包2头的长度等);包2;2字节crc;2字节包尾。(包2的包头部分,可以用RSA加密)
包2,也分为包头和包3:
2字节(命令号);2字节(报文序列号);2字节(设备地址);2字节(设备类型);扩展字节,通过参数控制长度(可保存EAS,标签等预留数据);包3(可以用AES加密)
包3:
用户根据(命令号)进行自定义,和扩增
43.在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他, 那么他将变成一个僵尸进程。即使是root身份kill -9也不能杀死僵尸进程。
第一种方式:signal(SIGCLD,SIG_IGN);忽略掉子进程发来的信号,系统释放
第二种方式:子进程死后,会发送SIGCHLD信号给父进程,父进程收到此信号后,执行waitpid()函数为子进程收尸。
参考:自己动手开发网络服务器(三)_九嶷山的博客-CSDN博客_自己动手开发网络服务器
42.开进程的时候,已经定义的文件描述符会相当于打开多次,需要每个进程分别关闭。
41.-Werror=maybe-uninitialized添加在编译里面,如果变量没有初始化就用到,就会报警,这样提高出错概率
40.qsort排序函数,bsearch二分法查找函数!
39.有时候我们会遇到:
struct mixer_simple_s {
uint8_t control_count; /**< number of inputs */
struct mixer_scaler_s output_scaler; /**< scaling for the output */
struct mixer_control_s controls[0]; /**< actual size of the array is set by control_count */
};
#define MIXER_SIMPLE_SIZE(_icount) (sizeof(struct mixer_simple_s) + (_icount) * sizeof(struct mixer_control_s))
mixinfo = (mixer_simple_s *)malloc(MIXER_SIMPLE_SIZE(inputs));
mixinfo->control_count = inputs;
这个结构体的大小是sizeof(mixer_simple_s)+(control_count-1)*sizeof(mixer_control_s).
38.配置进程优先级:
setpriority(PRIO_PROCESS, getpid(), -30);//范围: -20~20,越小优先级越高,需要root权限.
int priP = getpriority(PRIO_PROCESS, getpid());
int nice( int increment)
{
int oldprio = getpriority( PRIO_PROCESS, getpid());
return setpriority(PRIO_PROCESS, getpid(), oldprio + increment);
}
37.c++内容:
参考:https://baike.baidu.com/item/reinterpret_cast/9303204?fr=aladdin
char *a = new char;
double *b = reinterpret_cast <double*>(a);======(double *)a; 类的转换也一样,地址都是a的地址
static_cast 和dynamic_cast差不多,
1.不同类型不能转(报错),子类可以转为父类,且转换后是父类地址.
2.父类转为子类static_cast可以,可能崩溃;dynamic_cast不可以,如果可以但无子类返回是null. //本身父类转为子类是有问题的.除非父类是子类转来的.
const_cast需要相同类型,const转为变量类型
36.获取当前时区时间:
time_t now ;
struct tm *tm_now ;
time(&now) ;
now += _timeZoneHere * 3600;
tm_now = localtime(&now) ;
printf("now datetime: %d-%d-%d %d:%d:%d\n",tm_now->tm_year+1900, tm_now->tm_mon+1, tm_now->tm_mday, tm_now->tm_hour, tm_now->tm_min, tm_now->tm_sec);
//获得us级别的获取时间
struct timeval tv; //(1)
gettimeofday(&tv, NULL); //(2)上面的time函数也是调用的gettimeofday,得到秒部分.
获得系统启动的相对时间:
struct timespec
可以通过 int clock_gettime(clockid_t clk_id, struct timespec *tp)来获取
参数 clk_id : 检索和设置的clk_id指定的时钟时间。可以设置如下:
CLOCK_REALTIME:系统实时时间,随系统实时时间改变而改变,即从UTC1970-1-1 0:0:0开始计时,如果系统时间被用户改成其他,则对应的时间相应改变
CLOCK_REALTIME_COARSE:和CLOCK_REALTIME类似,但是执行速度快,精度低
CLOCK_MONOTONIC:从系统启动这一刻起开始计时,不受系统时间被用户改变的影响
CLOCK_MONOTONIC_COARSE :和CLOCK_MONOTONIC类似,但是执行速度快,精度低
CLOCK_BOOTTIME:和 CLOCK_MONOTONIC 类似,但是包括了系统休眠的时间。
CLOCK_PROCESS_CPUTIME_ID:本进程到当前代码系统CPU花费的时间
CLOCK_THREAD_CPUTIME_ID:本线程到当前代码系统CPU花费的时间
参数:tp 返回时间值
返回值 0成功, 1失败。
timeb结构体是标准库里得到ms级的,跨平台时使用
35.结构体:
struct tempStructTest
{
unsigned char a1 : 1; //0,表示a1站1位
unsigned char a2 : 2; //1
unsigned char a3 : 3; //3
unsigned char a4 : 4; //8,注意1个字节装不了更多的这四位,新开字节装
unsigned char a5 : 5; //16
};//大小为3字节
union workStatusFlag1{
struct
{
unsigned char a1 : 1; //0
unsigned char a2 : 2; //1
unsigned char a3 : 3; //3
unsigned char a4 : 4; //8
unsigned char a5 : 5; //16
};
unsigned int value;
} ap1;
tempStructTest useT = {//这里是初始化结构体:
a1 : 1,//区分与结构体定义的冒号与初始化结构体冒号的不同.
a2 : 2,
a3 : 6,
a4 : 1,
a5 : 2,
};
34.同33,定义了
A *myA = new A[100];
delete myA;//直接释放0,崩溃
释放时崩溃,需要:
delete [] myA;从最后99指针到0释放
33.类
class A
{
A(){A(100);}
A(int i){md=i;}
~A(){printf("free something!\n");}
int md;
};
上面的类我使用:
A a;
定义时打印了"free something!"
在函数结束时也打印了"free something!"
说明类定义时,调用了多次自己的构造函数,除了第一个构造函数外的其他构造函数会触发析构函数。
类的构造函数不能调用自己其他构造函数,否则定义类时触发析构函数。
32.带参数调用一个类的成员函数:
#include <stdio.h>
#define INVOKE_CLASS_FUNC(class,fun) (class.fun)
class invokeFunClass
{
public:
invokeFunClass(){}
~invokeFunClass(){}
int additionFun(int a, int b){return a + b;}
};
int main()
{
class invokeFunClass myc;
int a = 10;
int b = 220;
int c = INVOKE_CLASS_FUNC(myc, additionFun(a, b));
printf("c=%d\n", c);
}
31.结构体或类sizeof
struct ABCs
{
inline u8 & operator[](size_t i) { return reinterpret_cast<u8 *>(this)[i]; }
// inline u8 operator[](size_t i) { return reinterpret_cast<u8 *>(this)[i]; }
u8 data1;
u32 data2;
u16 data3;
}ABCv;
结构体中函数是不计算到sizeof的大小的。第一个数据以第一个变量开始。上面结构体12大小
union PACKED {
inline uint8_t &operator[](size_t i) { return reinterpret_cast<uint8_t *>(this)[i]; }
inline uint8_t operator[](size_t i) const { return reinterpret_cast<const uint8_t *>(this)[i]; }
ubx_nav_posllh posllh;
ubx_nav_status status;
ubx_nav_dop dop;
...
ubx_ack_ack ack;
} _buffer;
union的好处是以最大成员长度作为大小,结构体数据可以直接变。
class myClass
{
public:
myClass(){data = 0;}
~myClass(){}
//private:
static int addfun(int a){return data + a;}
int decfun(int a){return data - a;}
static int data;
int data1;
};
int myClass::data = 1;
大小为4,就是只有data1的大小,如果没有变量data1是1.静态变量不算到类大小中
30.有时候宏定义的地方太多,需要知道它实际的值:用#pragma message来打印。
- #define __PRINT_MACRO(x) #x
- #define PRINT_MACRO(x) #x"="__PRINT_MACRO(x)
- int main(int argc,const char*argv[])
- {
- #define TEST_MACRO 512
- #pragma message(PRINT_MACRO(TEST_MACRO))
- return 0;
- }
29.对于**p,*p[],(*p)[],p[][]的新的理解
*p[]表示一个数组,里面放的指针,指针指向到其他空间了。他也可以表示2维数组,但是与p[][]分配的空间不一样,p[][]是连续空间。(*p)[]缺点是:在C-C++中必须指定 [] 的长度
**p=*p[],(*p)[]=p[][]
在函数内分配空间,不能定义局部变量来分配,因为函数结束会释放。如果是带入参数来分配,带入参数的值在函数退出时恢复起始值。因此需要使用**p对其内容分配空间。全局变量就随便分配了。
28.不知道为什么主进程不能调用system函数,可以使用下面的函数来替代,但是缺少打印消息.
pclose(popen("echo ********************** >> /tmp/myfile", "r"));
27.directfb 用到了 __VA_ARGS__ 的用法。
#define dbg(format, ...) printf( format, ##__VA_ARGS__);
参考:#define qWiFiDebug(format, ...) qDebug("[WiFi] "format" File:%s, Line:%d, Function:%s", ##__VA_ARGS__, __FILE__, __LINE__ , __FUNCTION__);
第一:#define qWiFiDebug(format, ...)中,format是格式, ...是参数
第二:qDebug中的"[WiFi] "format" File:%s, Line:%d, Function:%s"是将format扩展到2个字符串之间。##__VA_ARGS__就是将...扩展到这里。
第三: ##__VA_ARGS__,参数__VA_ARGS__前面加##表示如果__VA_ARGS__没有参数的话,把##__VA_ARGS__前面的","去掉。因此加不加##看情况,下面是directfb中定义结构体的代码:
#define D_DEFINE_INTERFACE( IFACE, ... ) \
struct _ ## IFACE { \
void *priv; \
int magic; \
int refs; \
\
DirectResult (*AddRef)( IFACE *thiz ); \
DirectResult (*Release)( IFACE *thiz ); \
\
__VA_ARGS__ \
};
#define MY_ERR_DETECT(...) return __VA_ARGS__;有参数和无参数的返回一个函数即可
26.prtcl(PR_SET_NAME, ttname)可以设置本线程名字,在proc可以看statut来查名字。#include<sys/prctl.h>。prtcl还有其他功能
int pthread_setname_np(pthread_t thread, const char *name);设置指定线程的名字
25.pid_t,thread_t
创建线程的thread_t并不是/proc/pid/task/tid的。
获取进程id: getpid是获取进程的id,无论实在子线程里面还是进程都是同一个值。
获取/proc/pid/task/tid的id,可以:
#include <unistd.h>
#include <sys/syscall.h>
#define gettid() syscall(__NR_gettid)
pthread_self()也是获取thread_t的。
####################################################################################
1.register关键字尽可能将变量放到寄存器中,提高速度。对应变量不能大于int长度,不能使用&关键字,它会一直占用CPU寄存器,因此尽快用完退出,用于简短函数迅速处理。
如:register int a;
2.fprintf(stdout,"%d\n",100);fflush(stdout);打印消息时,用fflush冲洗stdout标准输出,提高本次打印速度,防止其他线程打印干扰。
3.以下代码是用来设计getchar不用输入回车。
#include<stdio.h>
#include <termios.h>
#include <unistd.h>
#include <errno.h>
int main()
{
int a;
struct termios term;
int err;
if(tcgetattr(STDIN_FILENO,&term)==-1)//获得标准输入的属性
{
perror("Cannot get standard input description");
return 1;
}
term.c_lflag &= ~(ICANON | ECHO);//修改属性
err=tcsetattr(STDIN_FILENO,TCSAFLUSH,&term);配置进去。
if(err==-1 && err==EINTR)
{
perror("Failed to change EOF character");
return 1;
}
while(1)
{
a = getchar();
printf("char=%c~int=%d\n", a, a);
}
return 1;
}
4.sizeof(void *)大小,32位是4,64位是8.
5.if(access("./myfile.txt", W_OK) == 0)
#define R_OK 4 /* Test for read permission. */
#define W_OK 2 /* Test for write permission. */
#define X_OK 1 /* Test for execute permission. */
#define F_OK 0 /* Test for existence. */
6.C与C++混合编程经常头文件用到:其中head.cpp定义了C++函数原型,head.h声明C++函数,main.c调用C++函数。C语言调用C++函数需要使用-lstdc++.
extern "C"表示下面内容用C语言编译和链接(因为要提示编译器用C编译和链接,因此在head.cpp(用c++编译)必须包含head.h头文件编译才能达到提示作用,或者在c++源代码用extern "C"包含)。作用:下面的代码既可以用C语言调用也可以用C++调用。
/head.h
#ifndef __HEAD_H__
#define __HEAD_H__
#ifdef __cplusplus//如果是C++编译器,使用C编译,和链接
extern "C"
{
#endif
int addFun(int a, int b);
#ifdef __cplusplus
}
#endif
#endif
/head.cpp
#include <stdio.h>
#include "head.h"
#include <iostream>
using namespace std;
int addFun(int a, int b)
{
cout<<a<<"+"<<b<<"="<<a+b<<endl;
return a+b;
}
/main.c
#include "head.h"
int main()
{
printf("%d\n", atoi(""));
return addFun(22,33);
}
/Makefile
all:
g++ -c head.cpp
gcc -c main.c
gcc -o main head.o main.o -lstdc++
clean:
rm *.o main
7.dup和dup2
#include <unistd.h>
int dup(int fd);将当前可用的最小的文件描述符指向fd,返回当前可用的最小的文件描述符.如果要将STDOUT_FILENO输出到fd,先close(STDOUT_FILENO);
int dup2(int fd, int fd2);fd2指向fd。返回fd2.输入到fd2的数据将输出到fd中,dup一样 输出到最小可用文件将输出到fd。
取消重定向:
#define fprintfdbg(stream, fmt, arg...) fprintf(stream, "[err-dbg:%s,%d]" fmt "\n", __FILE__, __LINE__, ##arg)
#define printfdbg(fmt, arg...) printf("[dbg:%s,%d]" fmt "\n", __FILE__, __LINE__, ##arg)
#define DY_LOG_FILE "ruslog.txt"
int main()
{
int stdfd = dup(STDOUT_FILENO);
unlink(DY_LOG_FILE);
int tmpLogfd = open(DY_LOG_FILE, O_RDWR | O_CREAT);
chmod(DY_LOG_FILE, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
fprintfdbg(stderr, "");//没有这两句打印,重定向有点问题。
printfdbg("%d,%d,%d", STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO);
dup2(tmpLogfd, STDERR_FILENO);
dup2(tmpLogfd, STDOUT_FILENO);
close(tmpLogfd);
printfdbg("mytest");
fprintfdbg(stdout, "1");
fprintfdbg(stderr, "2xx");
dup2(stdfd, STDOUT_FILENO);
printfdbg("");
system("echo xxxxxxxxxxxxxxxxxxxxxx;ls -l; echo aaaaaaaaaaaa;cat " DY_LOG_FILE);
return 0;
}
8.mkfifo("myfile", 0777);创建一个命名管道,一个进程读该文件,一个进程写文件即可。
如果我们要使用select或者poll,epoll来监听管道,需要在打开的时候设置O_RDWR可读写;如果使用O_RDONLY,第一次监听后,会poll会返回POLLHUP信号,一直返回成功.
listenPipeFd = open(DEAMON_FIFO_PATH, O_RDWR | O_NONBLOCK);//O_RDONLY
9.在main函数执行前会执行全局变量:C++中经常会这样用,不用定义类的对象就
class surApp
{
private:
static surApp tApp;
};
surApp surApp::tApp;
int main()
{
printf("%s,%d\n",__FILE__,__LINE__);
}
10.#include的特殊用法:
test.h/
//注意:这个头文件会多次被使用,所以不能加:#ifndef xxxx #define xxxx #endif.否则第一次包含这个头文件的时候将不会包含内容.
CBA(myfile1),
CBA(myfile2),
CBA(myfile3),
CBA(myfile4),
CBA(myfile5),
CBA(myfile6),
CBA(myfile7),
CBA(myfile8),
CBA(myfile9)
test1.h/
#define CBA(S) S//这里将宏定义指定格式
enum{
#include"test5.h"//实现宏格式。
};
main.cpp/
#include<stdio.h>
#include<iostream>
using namespace std;
const char *app[]={
#define CBA(s) ("mydirectory/"#s".txt")//这里将宏定义指定格式
#include"test5.h"//实现宏格式。
#undef CBA(S)//取消宏
};
#include"test1.h"//定义另外的一种输出格式。
int main()
{
int a1[] = {//test1.h定义了下面内容。
myfile6,
myfile7,
myfile8,
myfile9
};
cout<<sizeof(app)<<","<<a1[3]<<endl;
printf("[%s,%d]:%s\n",__FILE__,__LINE__,app[a1[0]]);
return 1;
}
11.try{}catch{}不能操作段错误。
#include <exception>
try{
throw 30;//自主抛出异常
}
catch(int k)//解析抛出的异常
{
switch(k)
{
case 30: printf("catch 30\n");
break;
}
}catch(exception &e)//比如STL调用异常,接收抛出消息
{
cout<<"catch error"<<endl;
cout<<e.what()<<endl;
}catch(...)
{
printf("error catch! \n");
}
12.条件变量需要和锁同时使用,用于数据同步:pthread_cond_wait可以让锁处于unlock状态,其他线程可以进入锁。
参考:http://blog.chinaunix.net/uid-26669601-id-3226291.html
初始化:
pthread_mutex_init(&mmutex, NULL);
pthread_cond_init(&mcond, NULL);
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;/*初始化互斥锁*/
pthread_cond_t mcond = PTHREAD_COND_INITIALIZER;//初始化条件变量
等待条件,和锁一起用:
pthread_mutex_lock(&mmutex);
c = pthread_cond_wait(&mcond, &mmutex);
pthread_mutex_unlock(&mmutex);
if (c) {
c = -1;
}
唤醒条件,和锁一起用:
pthread_mutex_lock(&mmutex);
c = pthread_cond_signal(&mcond);
pthread_mutex_unlock(&mmutex);
if (c) {
c = -1;
}
释放条件:
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&mcond);
13.删除文件:remove("file.txt");unlink("file.txt");
14.获取本机mac:SIOCGIFHWADDR、SIOCGIFADDR、SIOCGIFBRDADDR与SIOCGIFNETMASK作为参数调用函数ioctl分别获得MAC地址、IP地址、广播地址与子网掩码,SIOCGIFFLAGS获得ifr.ifr_flags网卡状态IFF_UP起来了,IFF_RUNNING正在运行。ifr.ifr_hwaddr.sa_data是mac,ifr.ifru_addr.sa_data是IP,ifr.ifru_broadaddr.sa_data是广播地址,ifr.ifru_netmask.sa_data子网掩码。参考:if2ip.h
struct ifreq ifr;
int sock, rval;
sock = socket(AF_INET,SOCK_DGRAM,0);
if(sock < 0) {
return (-1);
}
ifr.ifr_addr.sa_family = AF_INET;
strncpy(ifr.ifr_name, name, IFNAMSIZ-1);
if((rval = ioctl(sock, SIOCGIFHWADDR, &ifr)) == 0) {//SIOCGIFHWADDR获得硬件地址。
memcpy(mac, ifr.ifr_hwaddr.sa_data, 6);
}
close(sock);
15.c语言中的无限制参数:
void wpa_printf(int level, const char *fmt, ...)//跟printf差不多。
{
va_list ap;
va_start(ap, fmt);//获得fmt后的参数到ap。
if (level >= wpa_debug_level) {
vprintf(fmt, ap);//打印,跟printf一样,相当于ap就是后面跟的一些参数集合。
printf("\n");
}
va_end(ap);
}
#define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) )
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) ) //第一个可选参数地址
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) ) //下一个参数地址
#define va_end(ap) ( ap = (va_list)0 ) // 将指针置为无效
16.#define的使用:
#define ABC(M) #M //讲带入M参数转为字符串
#define CBA(M) 123_##M##_123 //表示将M与左右两边连接起来,作为一个整体。注意不是转换为字符串。
#include<stdio.h>
#define DF1(a) #a
#define DF2(b) __##b##__
#define FUN(a,b,c) \
do{ \
if(a){b;} \
else{c;} \
}while(0);
int DF2(wok)(void)
{
printf("fun=%s,%d,%s\n", __func__, __LINE__, __FILE__);
}
int main()
{
int i = 1;
printf("df1=%s,df2=\n",DF1(DF2(STRI)));
DF2(wok)();
FUN(i, {printf("function input %d\n", i);}, {printf("second function\n");});
return 0;
}
17.
symlink(a,b) 将a关联到b。意思就是a是本尊,b是个链接窗口,可以通过b访问a。
unlink(b)取消关联。
readlink(b,c,clen)b是一个链接符文件,将b链接到的文件a的地址放到c中,clen是c的长度。
if(flock(fileno(F_STREAM), LOCK_EX|LOCK_NB) < 0) {
这里有两个函数:fileno通过文件流得到对应的文件描述符。
flock将文件描述符锁住或者解锁。LOCK_EX创建锁。LOCK_NB创建失败,马上返回,LOCK_UN解锁,如下:
if((flock(fileno(fp_info), LOCK_UN)) < 0) {
18.目录操作:
DIR *pDir = NULL;
struct dirent* dt = NULL;
struct stat statbuf;
if((pDir=opendir(SESSION_DIRPATH)) == NULL){}打开一个目录。
while((dt=readdir(pDir)) != NULL){读取目录的一个文件/文件夹
//得到文件/文件夹的绝对路径
snprintf(filepath, sizeof(filepath)-1,"%s/%s", SESSION_DIRPATH, dt->d_name );
//获得文件/文件夹的状态
lstat(filepath, &statbuf);
//判断这个文件/文件夹是不是普通文件。
if(S_ISREG(statbuf.st_mode)){}
}
19.文件描述符:(来自wpa_supplicant,wpa_supplicant_fd_workaround)
标准输入描述符值为0
标准输出描述符值为1
标准错误输出描述符值为2
fd[i] = open("/dev/null", O_RDWR);
打开/dev/null就是打开最小的文件描述符,如果返回大于2,说明0,1,2都打开了。
20.stat:
struct stat buf;
int ret = stat(filename, &buf);//如果返回<0,说明没有该文件。0正常。很多地方可能就会用到stat来判断文件是不是存在。
if(0==ret) {
if(buf.st_mode & S_IFDIR)//判断是不是目录
return 0;
else
return 1;
}
21.typeof()获取一个地址的类型
int *x;
typeof(*x) y;
typeof(int *) y;
int *y;都一样
extern int foo();
typeof(foo()) var;
22.offsetof()获得结构体的偏移量。
#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})
定义一个member地址的类型 mptr, 地址mptr减去他在type结构体的偏移位置,从而计算出type类型实例的首地址。
23.指针加1不一定等于地址加1,而void*的类型和char*一致。
int a[2];
int *p = a;
void *b = a;
printf("a=%x,p+1=%x,b+1=%x\n", p+1, b+1);
输出:a=0x90add510,p+1=0x90add514,b+1=0x90add511.
24.WIFEXITED等函数用来判断子进程的。