C编程注意细微设计

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字节包头)
名称长度(字节)说明
包头30xa5,0x6c,0x93。防冲突
版本号10单片机协议
数据长度2小端,10长度表示0x0a,0x00。是数据区的长度。4+N
加密类型10无,1DES,其他
包校验1求和
数据区参考下面
命令2小端,10表示0x0a,0x00。命令应答需一致。
序列号1小端,10表示0x0a,0x00。命令应答需一致。
485地址10-254表示地址,255表示广播
数据内容N根据不同命令自定义
控制器六联按钮、语音、锁板的485协议。(波特率57600,数据位8,校验位'n',停止位1)(此协议20字节包头)
名称长度(字节)说明
包头30xa5,0x6c,0x93。防冲突
版本号11增强版
数据长度4小端,10长度表示0x0a,0x00,0x00,0x00。是数据区的长度。8+N
加密类型10无,1DES,其他
保留/压缩11:压缩
数据类型10:结构体格式,1:json格式
包校验1求和
数据区参考下面
命令2小端,10表示0x0a,0x00。命令应答需一致。
序列号2小端,10表示0x0a,0x00。命令应答需一致。
485地址10-254表示地址,255表示广播
设备类型11锁板,2六联按钮,3语音模块
应答10执行成功,其他表示特殊或错误代码
保留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来打印。

  1. #define __PRINT_MACRO(x) #x
  2. #define PRINT_MACRO(x) #x"="__PRINT_MACRO(x)
  3. int main(int argc,const char*argv[])
  4. {
  5. #define TEST_MACRO 512
  6. #pragma message(PRINT_MACRO(TEST_MACRO))
  7.         return 0;
  8. }

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);
}

stdarg.h头文件,有如下几个宏定义:

#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等函数用来判断子进程的。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值