Linux下C开发使用小技巧

基础类

整形,字符串互转

C语言提供了几个标准库函数,可以将任意类型(整型、长整型、浮点型等)的数字转换为字符串,下面列举了各函数的方法及其说明。 ● itoa():将整型值转换为字符串。 ● ltoa():将长整型值转换为字符串。 ● ultoa():将无符号长整型值转换为字符串。 ● gcvt():将浮点型数转换为字符串,取四舍五入。 ● ecvt():将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点。 ● fcvt():指定位数为转换精度,其余同ecvt()。

除此外,还可以使用sprintf系列函数把数字转换成字符串,其比itoa()系列函数运行速度慢

以下是用itoa()函数将整数转换为字符串的一个例子:

1
2
3
4
5
6
7
8
9
10
# include <stdio.h>
# include <stdlib.h>
void main (void)
{
int num = 100;
char str[25];
itoa(num, str, 10);
printf("The number 'num' is %d and the string 'str' is %s. \n" ,
num, str);
}

itoa()函数有3个参数:第一个参数是要转换的数字,第二个参数是要写入转换结果的目标字符串,第三个参数是转移数字时所用 的基数。在上例中,转换基数为10。10:十进制;2:二进制…

itoa并不是一个标准的C函数,它是Windows特有的,如果要写跨平台的程序,请用sprintf。是Windows平台下扩展的,标准库中有sprintf,功能比这个更强,用法跟printf类似:

1
2
char str[255];
sprintf(str, "%x", 100); //将100转为16进制表示的字符串。

cpp中string转int:

1
2
3
4
void str2int(int &int_temp,const string &string_temp)  
{
int_temp=atoi(string_temp.c_str());
}

cpp中int转string:

1
2
3
4
5
6
void int2str(const int &int_temp,string &string_temp)  
{
char s[12]; //设定12位对于存储32位int值足够
itoa(int_temp,s,10); //itoa函数亦可以实现,但是属于C中函数,在C++中推荐用流的方法
string_temp=s;
}

架构类

Linux C代码实现主函数参数选项解析

1. 手动解析版本

使用argc、argv,逐个字符比较,得到要想的参数名字即进行判断、解析。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int debug;

void show_version(char* name)
{
printf("%s by Late Lee, version: 1.0\n", name);
}

void usage(char* name)
{
show_version(name);

printf(" -h, --help short help\n");
printf(" -v, --version show version\n");
}

int main(int argc, char *argv[])
{
int i = 0;

/* early check for debug and config parameter */
if (argc > 1) {
for (i = 1; i < argc; i++)
{
if ((strcmp(argv[i], "-D")==0) || (strcmp(argv[i], "--debug")==0))
{
debug = 1;
}
}
}

//
/* parse parameters, maybe not the best way but... */
for (i = 1; i < argc; i++)
{
if (debug)
printf("arg %d: \"%s\"\n",i,argv[i]);
// help
if ((strcmp(argv[i],"-h")==0) || (strcmp(argv[i],"--help")==0))
{
usage(argv[0]);
return 0;
}
// version
else if ((strcmp(argv[i],"-v")==0) || (strcmp(argv[i],"--version")==0))
{
show_version(argv[0]);
return 0;
}
// debug
else if ((strcmp(argv[i],"-D")==0) || (strcmp(argv[i],"--debug")==0))
{
debug=1;
}
else if ((strcmp(argv[i],"fpga")==0))
{
printf("test of fpga...\n");
}
// string
else if ((strcmp(argv[i],"-i")==0) || (strcmp(argv[i],"--iface")==0))
{
if (i+1<argc)
{
char interface[32] = {0};
strncpy(interface, argv[i+1], 32);
if (debug)
printf("Used interface: %s\n", interface);
i++;
continue;
} else {
printf("Error: Interface for -i missing.\n");
return 1;
}
}
// number
else if ((strcmp(argv[i],"-ru")==0) || (strcmp(argv[i],"--rateunit"))==0)
{
if (i+1<argc && isdigit(argv[i+1][0])) {
int rateunit = 0;
rateunit = atoi(argv[i+1]);
if (rateunit < 0 || rateunit > 1)
{
printf("Error: Invalid parameter \"%d\" for --rateunit.\n", rateunit);
printf(" Valid parameters:\n");
printf(" 0 - bytes\n");
printf(" 1 - bits\n");
return 1;
}
if (debug)
printf("Rateunit changed: %d\n", rateunit);
i++;
continue;
}
else
{
}
}
// only one
else if (strcmp(argv[i],"--enable")==0)
{
int enable = 0;
enable = 1;
}
else
{
printf("Unknown parameter \"%s\". Use --help for help.\n",argv[i]);
return 1;
}
}
}
2. 利用getopt函数完成
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
/**
解析命令选项示例

#include <unistd.h>
extern char *optarg; //选项的参数指针
extern int optind, //下一次调用getopt的时,从optind存储的位置处重新开始检查选项。
extern int opterr, //当opterr=0时,getopt不向stderr输出错误信息。
extern int optopt; //当命令行选项字符不包括在optstring中或者选项缺少必要的参数时,该选项存储在optopt中,getopt返回'?’、
int getopt(int argc, char * const argv[], const char *optstring);

使用:
$ ./a.out -Wall -o hello.c

*/
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>

int debug_level = 0;

#define _AUTHOR "Late Lee"
#define _VERSION_STR "1.0"
#define _DATE ""

// 默认打印error等级
enum
{
MSG_ERROR = 0,
MSG_WARNING,
MSG_INFO,
MSG_DEBUG,
MSG_MSGDUMP,
MSG_EXCESSIVE,
};

void ll_printf(int level, const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));

void ll_printf(int level, const char *fmt, ...)
{
va_list ap;

va_start(ap, fmt);
if (debug_level >= level)
{
#ifdef CONFIG_DEBUG_SYSLOG
if (wpa_debug_syslog) {
vsyslog(syslog_priority(level), fmt, ap);
} else {
#endif /* CONFIG_DEBUG_SYSLOG */
//debug_print_timestamp();
#ifdef CONFIG_DEBUG_FILE
if (out_file) {
vfprintf(out_file, fmt, ap);
fprintf(out_file, "\n");
} else {
#endif /* CONFIG_DEBUG_FILE */
vprintf(fmt, ap);
printf("\n");
#ifdef CONFIG_DEBUG_FILE
}
#endif /* CONFIG_DEBUG_FILE */
#ifdef CONFIG_DEBUG_SYSLOG
}
#endif /* CONFIG_DEBUG_SYSLOG */
}
va_end(ap);
}

void show_version(char* name)
{
printf("%s by %s, version: %s\n", name, _AUTHOR, _VERSION_STR);
}

void usage(char* name)
{
show_version(name);

printf(" -h, short help\n");
printf(" -v, show version\n");
printf(" -d, debug level\n");

exit(0);
}

const char* my_opt = "hOo:W:d:";

int main(int argc, char *argv[])
{
int c;
const char* p1 = NULL;
const char* p2 = NULL;
const char* p3 = NULL;
while(1)
{
c = getopt(argc, argv, my_opt);
printf("optind: %d\n", optind);
if (c < 0)
{
break;
}
printf("option char: %x %c\n", c, c);
switch(c)
{
case 'd':
debug_level = atoi(optarg);
printf("debug level: %d\n", debug_level);
break;
case 'O':
printf("optimization flag is open.\n\n");
break;
case 'o':
printf("the obj is: %s\n\n", optarg);
p1 = optarg;
break;
case 'W':
printf("optarg: %s\n\n", optarg);
p2 = optarg;
break;
case ':':
fprintf(stderr, "miss option char in optstring.\n");
break;
case '?':
case 'h':
default:
usage(argv[0]);
break;
//return 0;
}
}
if (optind == 1)
{
usage(argv[0]);
}

ll_printf(MSG_ERROR, "p1: %s p2: %s\n", p1, p2);

return 0;
}

使用 getopt() 进行命令行处理

网络模块

日志模块

读取配置文件模块

内存池模块

缓存库模块

文件系统模块

管理后台模块

数据库模块

技巧类

Linux程序中预定义的几个调试宏

Linux下C语言编程中有几个很实用的调试宏

1
__LINE__ __FILE__  __FUNCTION__ __TIME__ __DATA__

这几个预定义宏是属于ANSI标准的,内置于编译器,全局性的变量,可以方便地实现代码跟踪调试,不是在哪个头文件中包含的,见下例:

1
2
3
4
5
6
7
8
9
10
11
#include <stdio.h>

int main()
{
printf("The file is %s.\n",__FILE__);
printf( "The date is %s.\n", __DATE__ );
printf( "The time is %s.\n", __TIME__ );
printf( "This is line %d.\n", __LINE__ );
printf( "This function is %s.\n", __FUNCTION__ );
return 0;
}

运行结果:

1
2
3
4
5
The file is macro.c.
The date is Aug 24 2012.
The time is 23:13:26.
This is line 8.
This function is main.

line 行数 文件名指令可以改变它的值,简单的讲,编译时,它们包含程序的当前行数和文件名。

DATE 宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。 TIME 宏指令包含程序编译的时间。时间用字符串表示,其形式为时:分:秒

__func__代表这条语句所在的函数的函数名

联合体用途

字节序有两种表示方法:大端法(big ending),小端法(little ending)。网络字节序采用的是大端法。主机字节序不同的CPU采用的方法不一样,可以通过代码来查看自己主机的字节序。

  • 大端法:高位字节排放在内存低地址端,低位字节排放在内存的高地址端。
  • 小端法:低位字节排放在内存的低地址端,高位字节排放在内存的高地址端。 看一个unsigned short 数据,它占2个字节,给它赋值0x1234。
  • 若采用的大端法,则其低地址端应该存放的是0x12;
  • 若采用的小端法,则其低地址端应该存放的是0x34; 可以通过联合体来获得其高低地址的数据。测试主机字节序的代码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    typedef union{
    unsigned short value;
    unsigned char bytes[2];
    }Test;

    int main(void)
    {
    Test test_value;
    test_value.value = 0x1234;
    if(test_value.bytes[0] == 0x12 && test_value.bytes[1] == 0x34)
    {
    printf("big ending");
    }
    else if(test_value.bytes[0] == 0x34 && test_value.bytes[1] == 0x12)
    {
    printf("little ending");
    }else{
    printf("use test_value error");
    }
    return 0;
    }

工具类

自定义日志的调试打印信息

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#define TRACE_NONE      0
#define TRACE_FATAL 1
#define TRACE_ERROR 2
#define TRACE_WARNING 3
#define TRACE_INFO 4
#define TRACE_DEBUG 5

#define TRACE_LEN_MAX 64

extern int *TraceLevel;
extern char TraceName[TRACE_LEN_MAX + 1];

#define Log(A, format,args...) \
((TraceLevel == NULL || TraceName == NULL || *TraceLevel < (A)) ? 0 : LogMsg(A, __FILE__, __LINE__, format, ##args))

#define LogFatal(format,args...) \
Log(TRACE_FATAL, format, ##args)
#define LogError(format,args...) \
Log(TRACE_ERROR, format, ##args)
#define LogWarning(format,args...) \
Log(TRACE_WARNING, format, ##args)
#define LogInfo(format,args...) \
Log(TRACE_INFO, format, ##args)
#define LogDebug(format,args...) \
Log(TRACE_DEBUG, format, ##args)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
int LogMsg(int level, const char *filename,
int line, const char *fmt, ...)
{
va_list ap;
FILE *fp;
char sLogFile[128 + 1];
char sCurrTime[6 + 1];
struct timeb tTimeB;
char sMilliTM[4];

memset(sLogFile, 0, sizeof(sLogFile));
LogFile(sLogFile);
GetTime_HHMMSS(sCurrTime);
memset(&tTimeB, 0, sizeof(tTimeB));
ftime(&tTimeB);
snprintf(sMilliTM, sizeof(sMilliTM), "%03d", tTimeB.millitm);

fp = fopen(sLogFile, "a+");
if (fp != (FILE*)NULL) {
fprintf(fp, "[%08d][%.6s:%.3s][%16s][%04d][%7s]",
getpid(), sCurrTime, sMilliTM, filename, line, g_LevelDsp[level]);
va_start(ap, fmt);
vfprintf(fp, fmt, ap);
va_end(ap);
fprintf(fp, "\n");
fflush(fp);
fclose(fp);
}

return 0;
}

再在后台进程中设置TraceLevel和TraceName即可。

获取当前系统日期、时间

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*****************************************************************************
** 函数名称: GetDate
** 功能描述: 取当前系统日期
** 当前版本: 1.0.0.0
** 作 者:
** 修 改:
** 输入参数:
** 输出参数: char * psDate -- 系统日期, 格式为yyyymmdd
** 返回结果:int
0 ---> 成功
****************************************************************************/
int GetDate(char * psDate)
{
time_t nSeconds;
struct tm * pTM;

time(&nSeconds);
pTM = localtime(&nSeconds);

/* 系统日期, 格式:YYYYMMDD */
sprintf( psDate,"%04d%02d%02d",
pTM->tm_year + 1900, pTM->tm_mon + 1,pTM->tm_mday );

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/*****************************************************************************
** 函数名称: GetTime
** 功能描述: 取当前系统时间
** 当前版本: 1.0.0.0
** 作 者:
** 修 改:
** 输入参数:
** 输出参数: char * psTime -- 系统时间, 格式为HHMMSS
** 返回结果:int
0 ---> 成功
****************************************************************************/
int GetTime(char * psTime)
{
time_t nSeconds;
struct tm * pTM;

time(&nSeconds);
pTM = localtime(&nSeconds);

/* 系统时间, 格式:HHMMSS */
sprintf( psTime,"%02d%02d%02d",
pTM->tm_hour,pTM->tm_min, pTM->tm_sec);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*****************************************************************************
** 函数名称: GetDateTime
** 功能描述: 取当前系统日期和时间
** 当前版本: 1.0.0.0
** 作 者:
** 修 改:
** 输入参数:
** 输出参数: char * psDateTime -- 系统日期时间, 格式为yyyymmddHHMMSS
** 返回结果:int
0 ---> 成功
****************************************************************************/
int GetDateTime(char * psDateTime)
{
time_t nSeconds;
struct tm * pTM;

time(&nSeconds);
pTM = localtime(&nSeconds);

/* 系统日期和时间, 格式:yyyymmddHHMMSS */
sprintf( psDateTime,"%04d%02d%02d%02d%02d%02d",
pTM->tm_year + 1900, pTM->tm_mon + 1,pTM->tm_mday,
pTM->tm_hour,pTM->tm_min, pTM->tm_sec );

return 0;
}

调用的时候定义一个char数组,大小为日期的长度大小加1,然后直接调用上面的函数,参数为数组名即可。   当然,还有其他许多关于日期、时间操作的函数,比如不同日期、时间格式间的转换等。

坚持原创技术分享,您的支持将鼓励我继续创作!