Linux下C开发使用小技巧
Linux下C开发使用小技巧
基础类
整形,字符串互转
C语言提供了几个标准库函数,可以将任意类型(整型、长整型、浮点型等)的数字转换为字符串,下面列举了各函数的方法及其说明。
● itoa():将整型值转换为字符串。
● ltoa():将长整型值转换为字符串。
● ultoa():将无符号长整型值转换为字符串。
● gcvt():将浮点型数转换为字符串,取四舍五入。
● ecvt():将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点。
● fcvt():指定位数为转换精度,其余同ecvt()。
除此外,还可以使用sprintf系列函数把数字转换成字符串,其比itoa()系列函数运行速度慢
以下是用itoa()函数将整数转换为字符串的一个例子:
# 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类似:
char str[255];
sprintf(str, "%x", 100); //将100转为16进制表示的字符串。
cpp中string转int:
void str2int(int &int_temp,const string &string_temp)
{
int_temp=atoi(string_temp.c_str());
}
cpp中int转string:
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,逐个字符比较,得到要想的参数名字即进行判断、解析。
#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函数完成
/**
解析命令选项示例
#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语言编程中有几个很实用的调试宏
__LINE__ __FILE__ __FUNCTION__ __TIME__ __DATA__
这几个预定义宏是属于ANSI标准的,内置于编译器,全局性的变量,可以方便地实现代码跟踪调试,不是在哪个头文件中包含的,见下例:
#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;
}
运行结果:
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;
可以通过联合体来获得其高低地址的数据。测试主机字节序的代码:
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;
}
工具类
自定义日志的调试打印信息
#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)
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即可。
获取当前系统日期、时间
/*****************************************************************************
** 函数名称: 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;
}
/*****************************************************************************
** 函数名称: 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;
}
/*****************************************************************************
** 函数名称: 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,然后直接调用上面的函数,参数为数组名即可。
当然,还有其他许多关于日期、时间操作的函数,比如不同日期、时间格式间的转换等。