当前位置:网站首页>Skills of embedded C language program debugging and macro use
Skills of embedded C language program debugging and macro use
2022-07-07 18:20:00 【Luo Hanxiang】
Link to the original text : The embedded C Language program debugging and macro use skills
1. Debug related macro
stay Linux Use gcc When compiling a program , There are also some special syntax for debugging statements .gcc During compilation , It will generate some macros , You can use these macros to print information about the current source file separately , The main content is the current document 、 The current running function and the current program line .
The specific macro is as follows
__FILE__ Current program source file (char*)
__FUNCTION__ Currently running functions (char*)
__LINE__ The current function line (int)
: These macros are not defined by program code , It's produced by a compiler . This information is generated dynamically when the compiler processes files .
Test examples :
#include <stdio.h>
int main(void)
{
printf("file: %s\n", __FILE__);
printf("function: %s\n", __FUNCTION__);
printf("line: %d\n", __LINE__);
return 0;
}
2. # String operators
stay gcc In the compiler system , have access to # Convert the current content to a string .
Program example :
#include <stdio.h>
#define DPRINT(expr) printf("<main>%s = %d\n", #expr, expr);
int main(void)
{
int x = 3;
int y = 5;
DPRINT(x / y);
DPRINT(x + y);
DPRINT(x * y);
return 0;
}
Execution results :
[email protected]:~/tmp$ gcc test.c
[email protected]:~/tmp$ ./a.out
<main>x / y = 0
<main>x + y = 8
<main>x * y = 15
#expr Indicates that according to the parameters in the macro ( The content of the expression ), Generate a string . The process is also generated by the compiler , When the compiler compiles the source file , If you encounter a macro like this , Automatically according to the content of the expression in the program , Macro that generates a string .
The advantage of this method is that the content of the expression can be printed in a unified way , In the debugging process of the program, you can easily and intuitively see the expression after the conversion string . What is the content of the specific expression , There are compilers that automatically write to programs , This uses the same macro to print the string of all expressions .
// Print character
#define debugc(expr) printf("<char> %s = %c\n", #expr, expr)
// Print floating-point numbers
#define debugf(expr) printf("<float> %s = %f\n", #expr, expr)
// according to 16 Print integers in decimal
#define debugx(expr) printf("<int> %s = 0X%x\n", #expr, expr);
because #expr Essentially listing a macro that represents a string , Therefore, it can not be applied in the program %s Print its content , Instead, it can be connected directly to other strings . therefore , The above macro can be equivalent to the following form :
// Print character
#define debugc(expr) printf("<char> #expr = %c\n", expr)
// Print floating-point numbers
#define debugf(expr) printf("<float> #expr = %f\n", expr)
// according to 16 Print integers in decimal
#define debugx(expr) printf("<int> #expr = 0X%x\n", expr);
summary :
# yes C String operator in language preprocessing stage , You can convert the contents of a macro to a string .
3. ## Join operators
stay gcc In the compiler system ,## yes C The join operator in language , String concatenation can be implemented in the preprocessing stage of compilation .
Program example :
#include <stdio.h>
#define test(x) test##x
void test1(int a)
{
printf("test1 a = %d\n", a);
}
void test2(char *s)
{
printf("test2 s = %s\n", s);
}
int main(void)
{
test(1)(100);
test(2)("hello world");
return 0;
}
In the above procedure ,test(x) A macro is defined as test##x, He said test String and x String connection .
In the debug statement of a program ,## The common way is as follows
#define DEBUG(fmt, args...) printf(fmt, ##args)
The way to replace it is to change the two parts of the parameter with ## Connect .## Indicates that the connection variable represents the previous parameter list . In this form, you can pass a macro's argument to an argument .args… Is an argument to a macro , Represents a variable parameter list , Use ##args Pass it on to printf function .
summary :
## yes C The join operator of language preprocessing stage , It can realize the connection of macro parameters .
4. Debug macro first form
A way of defining :
#define DEBUG(fmt, args...) \
{ \
printf("file:%s function: %s line: %d ", __FILE__, __FUNCTION__, __LINE__);\
printf(fmt, ##args); \
}
Program example :
#include <stdio.h>
#define DEBUG(fmt, args...) \
{ \
printf("file:%s function: %s line: %d ", __FILE__, __FUNCTION__, __LINE__);\
printf(fmt, ##args); \
}
int main(void)
{
int a = 100;
int b = 200;
char *s = "hello world";
DEBUG("a = %d b = %d\n", a, b);
DEBUG("a = %x b = %x\n", a, b);
DEBUG("s = %s\n", s);
return 0;
}
summary :
above DEBUG The way it is defined is a combination of two statements , It is not possible to generate a return value , So you can't use its return value .
5. The second way to define a debug macro
The second way to define a debug macro
#define DEBUG(fmt, args...) \
printf("file:%s function: %s line: %d "fmt, \
__FILE__, __FUNCTION__, __LINE__, ##args)
Program example
#include <stdio.h>
#define DEBUG(fmt, args...) \
printf("file:%s function: %s line: %d "fmt, \
__FILE__, __FUNCTION__, __LINE__, ##args)
int main(void)
{
int a = 100;
int b = 200;
char *s = "hello world";
DEBUG("a = %d b = %d\n", a, b);
DEBUG("a = %x b = %x\n", a, b);
DEBUG("s = %s\n", s);
return 0;
}
summary :
fmt Must be a string , You can't use a pointer , Only in this way can we realize the function of string .
6. Review debugging statements in different levels
Even if the macro for debugging is defined , When the project is big enough , It also causes a lot of information in the terminal when the macro switch is turned on . And there's no way to tell what's useful . At this time, it is necessary to add a hierarchical inspection mechanism , You can define different debugging levels , In this way, different important programs and different modules can be distinguished , You can open the debug level of that module by debugging it .
Generally, you can use the configuration file to display , Actually Linux The kernel does the same thing , It divides the level of debugging into 7 Different levels of importance , Only set a certain level to display , The corresponding debugging information will be printed to the terminal .
You can write out the configuration file
[debug]
debug_level=XXX_MODULE
Parsing the configuration file uses standard string manipulation library functions to get XXX_MODULE The numerical .
int show_debug(int level)
{
if (level == XXX_MODULE)
{
#define DEBUG(fmt, args...) \
printf("file:%s function: %s line: %d "fmt, \
__FILE__, __FUNCTION__, __LINE__, ##args)
}
else if (...)
{
....
}
}
7. Conditional compilation debugging statements
In actual development , Two kinds of source programs are generally maintained , One is a debug version program with debug statements , The other is a release program without debugging statements . Then compile the options according to different conditions , Compile different debug and release versions of the program .
In the process of implementation , You can use a debug macro to control the switch of debugging statements .
#ifdef USE_DEBUG
#define DEBUG(fmt, args...) \
printf("file:%s function: %s line: %d "fmt, \
__FILE__, __FUNCTION__, __LINE__, ##args)
#else
#define DEBUG(fmt, args...)
#endif
If USE_DEBUG Defined , So there's debugging information , otherwise DEBUG It's empty .
If you need debugging information , Just change one line in the program .
#define USE_DEBUG
#undef USE_DEBUG
Define how conditional compilation works using a macro with values
#if USE_DEBUG
#define DEBUG(fmt, args...) \
printf("file:%s function: %s line: %d "fmt, \
__FILE__, __FUNCTION__, __LINE__, ##args)
#else
#define DEBUG(fmt, args...)
#endif
Conditional compilation can be done in the following ways
#ifndef USE_DEBUG
#define USE_DEBUG 0
#endif
8. Use do…while The macro definition of
Using macro definition can encapsulate some shorter functions , Easy to use . The form of a macro is similar to a function , But it can save the cost of function jump . How to encapsulate a statement into a macro , It is often used in programs do…while(0) In the form of .
#define HELLO(str) do { \
printf("hello: %s\n", str); \
}while(0)
Program example :
int cond = 1;
if (cond)
HELLO("true");
else
HELLO("false");
9. Code analysis
For larger programs , You can use some tools to clean up the points that need to be optimized first . Next, let's take a look at the tools for getting data and analyzing it during program execution : Code parser .
The test program :
#include <stdio.h>
#define T 100000
void call_one()
{
int count = T * 1000;
while(count--);
}
void call_two()
{
int count = T * 50;
while(count--);
}
void call_three()
{
int count = T * 20;
while(count--);
}
int main(void)
{
int time = 10;
while(time--)
{
call_one();
call_two();
call_three();
}
return 0;
}
When compiling, add -pg Options :
[email protected]:~/tmp$ gcc -pg test.c -o test
After execution , A... Is generated in the current file gmon.out file .
[email protected]:~/tmp$ ./test
[email protected]:~/tmp$ ls
gmon.out test test.c
[email protected]:~/tmp$
Use gprof Dissect the main program :
[email protected]:~/tmp$ gprof test
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
95.64 1.61 1.61 10 160.68 160.68 call_one
3.63 1.67 0.06 10 6.10 6.10 call_two
2.42 1.71 0.04 10 4.07 4.07 call_three
There are two main messages , One is the percentage of execution time of each function in the total program time , The other is the number of times a function is called . Through this information , Can optimize the implementation of the core program to improve efficiency .
Of course, this parser has some limitations due to its own characteristics , It is more suitable for programs that run for a long time , Because the statistical time is based on the interval counting mechanism , So we also need to consider the relative time of function execution , If the program execution time is too short , The information we get is of no reference significance .
Shorten the appeal process :
#include <stdio.h>
#define T 100
void call_one()
{
int count = T * 1000;
while(count--);
}
void call_two()
{
int count = T * 50;
while(count--);
}
void call_three()
{
int count = T * 20;
while(count--);
}
int main(void)
{
int time = 10;
while(time--)
{
call_one();
call_two();
call_three();
}
return 0;
}
The analysis results are as follows :
[email protected]:~/tmp$ gcc -pg test.c -o test
[email protected]:~/tmp$ ./test
[email protected]:~/tmp$ gprof test
Flat profile:
Each sample counts as 0.01 seconds.
no time accumulated
% cumulative self self total
time seconds seconds calls Ts/call Ts/call name
0.00 0.00 0.00 10 0.00 0.00 call_one
0.00 0.00 0.00 10 0.00 0.00 call_three
0.00 0.00 0.00 10 0.00 0.00 call_two
So the more complex the profiling program is for 、 Functions that take longer to execute also apply .
So the longer the absolute time each function takes to execute , The longer it takes to dissect and show ? Here's another example
#include <stdio.h>
#define T 100
void call_one()
{
int count = T * 1000;
while(count--);
}
void call_two()
{
int count = T * 100000;
while(count--);
}
void call_three()
{
int count = T * 20;
while(count--);
}
int main(void)
{
int time = 10;
while(time--)
{
call_one();
call_two();
call_three();
}
return 0;
}
The analysis results are as follows :
[email protected]:~/tmp$ gcc -pg test.c -o test
[email protected]:~/tmp$ ./test
[email protected]:~/tmp$ gprof test
Flat profile:
Each sample counts as 0.01 seconds.
% cumulative self self total
time seconds seconds calls ms/call ms/call name
101.69 0.15 0.15 10 15.25 15.25 call_two
0.00 0.15 0.00 10 0.00 0.00 call_one
0.00 0.15 0.00 10 0.00 0.00 call_three
summary :
In the use of gprof When it comes to tools , For a function gprof Analysis of the way , Time in essence refers to the exception of library function calls and system calls , The running time of the actual code developed by the pure application part .
in other words ,time The time value of a description does not include library functions printf、 system call system Wait for the running time . Although the programs of these utility library functions are running , It will take more time than the original program , But it doesn't affect parsing functions .
边栏推荐
- SD_DATA_RECEIVE_SHIFT_REGISTER
- Classification of regression tests
- JS pull down the curtain JS special effect display layer
- 回归问题的评价指标和重要知识点总结
- 科学家首次观察到“电子漩涡” 有助于设计出更高效的电子产品
- How to implement safety practice in software development stage
- Management by objectives [14 of management]
- Machine vision (1) - Overview
- 小试牛刀之NunJucks模板引擎
- Use onedns to perfectly solve the optimization problem of office network
猜你喜欢
[trusted computing] Lesson 13: TPM extended authorization and key management
Improve application security through nonce field of play integrity API
Test for 3 months, successful entry "byte", my interview experience summary
物联网OTA技术介绍
Introduction of common API for socket programming and code implementation of socket, select, poll, epoll high concurrency server model
万字保姆级长文——Linkedin元数据管理平台Datahub离线安装指南
Machine vision (1) - Overview
海量数据去重的hash,bitmap与布隆过滤器Bloom Filter
Tear the Nacos source code by hand (tear the client source code first)
ICer知识点杂烩(后附大量题目,持续更新中)
随机推荐
What is agile testing
Youth experience and career development
Based on pytorch, we use CNN to classify our own data sets
TaffyDB开源的JS数据库
AI 击败了人类,设计了更好的经济机制
SD_DATA_RECEIVE_SHIFT_REGISTER
Tear the Nacos source code by hand (tear the client source code first)
Chapter 3 business function development (user login)
[4500 word summary] a complete set of skills that a software testing engineer needs to master
小程序中实现付款功能
Self made dataset in pytoch for dataset rewriting
现货白银分析中的一些要点
[trusted computing] Lesson 10: TPM password resource management (II)
【demo】循环队列及条件锁实现goroutine间的通信
Tips of this week 141: pay attention to implicit conversion to bool
万字保姆级长文——Linkedin元数据管理平台Datahub离线安装指南
云景网络科技面试题【杭州多测师】【杭州多测师_王sir】
Click on the top of today's headline app to navigate in the middle
[principles and technologies of network attack and Defense] Chapter 5: denial of service attack
“解密”华为机器视觉军团:华为向上,产业向前