当前位置:网站首页>Talk about "in C language"
Talk about "in C language"
2022-07-04 12:29:00 【ysds20211402】
from : Micro reading https://www.weidianyuedu.com
There are many popular programming languages on the market , such as Python、 JAVA、 Go etc. , You may think C Language is very old 、 Very backward . If you have that thought , Maybe you're just a beginner . Share with you before 《C Several special standard definitions and usages in language 》 Forget the C An important part of language , Namely ## Usage of , Probably most C Programmers don't know "##" Hide usage , Now let's talk about .
One 、## Of “ surface ” usage
Many people must know "##" Usage of —— It's essentially a “ Glue operation ”( The function of connection string ), Used to put... In the parameter macro “ Shape parameter ” Stick with other content without natural segmentation , for example :
#define def_u32_array(__name, __size) uint32_t array_##__name[__size];
In the actual , We can use :
def_u32_array(sample_buffer, 64)
The effect of macro expansion is :
uint32_t array_sample_buffer[64];
You can see ,"array__" Formal parameter “__name” There is no natural division , So if you want to "array_" And "__name" What it represents ( instead of __name In itself ) Stick together , Need “##” The help of arithmetic .
On the other hand ,"__name" And "[" It has natural separation —— The compiler doesn't think "__name" And "[" It's connected , Therefore, there is no need to paint a snake to add feet "##" operation —— If you do , The precompiler will not hesitate to tell you the syntax error .—— This is a "##" Common usage of operations , Articles reprinted in the past 《C Language # and ## The application of connectors in projects ( beautiful )》 It is also described in detail in , No more details here .
Two 、## The official “ in ” usage
“##” There is another little-known “ in ” usage , Before introducing it , I have to start with ANSI-C99 Another parameter macro extension introduced by the standard —— Variable parameter macro . for instance :
#define safe_atom_code(...) \
{ \
uint32_t int_flag = __disable_irq(); \
__VA_ARGS__ \
__set_PRIMASK(int_flag); \
}
A macro is defined here "safe_atom_code()", In brackets , Whatever you fill in , Will be unconditionally placed in “__VA_ARGS__” Where it is , You can think of... In parentheses “...” In fact, it corresponds to "__VA_ARGS__". such as , We can write such code :
/**
\fn void wr_dat (uint16_t dat)
\brief Write data to the LCD controller
\param[in] dat Data to write
*/
static __inline void wr_dat (uint_fast16_t dat)
{
safe_atom_code(
LCD_CS(0);
GLCD_PORT->DAT = (dat >> 8); /* Write D8..D15 */
GLCD_PORT->DAT = (dat & 0xFF); /* Write D0..D7 */
LCD_CS(1);
)
}
This code ensures that the register GCLD_PORT->DAT Writing data will not be interrupted by other interrupts .
Smart you may ask such a question soon , What is the difference between the above macro and the following macro ?
#define safe_atom_code(__CODE) \
{ \
uint32_t int_flag = __disable_irq(); \
__CODE \
__set_PRIMASK(int_flag); \
}
You're not just asking questions , Even actually tested , It seems to be completely equivalent ,“ No difference at all !”—— You exclaimed . However , In fact, it's not that simple :
1. The parameter macro is through “,” As a separator to calculate the actual output of the user, which has passed in several parameters , Or to put it another way , When using parameter macros , The precompiler doesn't understand C The grammatical —— In its eyes , Except for a few symbols it knows , Everything else is a meaningless string —— Because when dealing with the contents inside parentheses , It only knows "," and "...", Therefore, when the content in parentheses is increased by one ",", And the compiler think there is one more parameter .
2. When you use parameter macros , Number of parameters passed in ( has “,” Separate ) It must be exactly the same as the number of formal parameters when defining parameter macros ; When inconsistent , The precompiler may not report an error , But directly ignore your parameter macro —— Pass it to the next stage of compilation , Therefore, it is often regarded as a function —— In fact, this function does not exist , Therefore, an undefined error of a certain function will be reported in the link phase . Then you'll wonder , Why do I clearly define a macro , The compiler treats it as a function ?
The introduction of variable macro parameters solves this problem :
"..." It can only be placed at the end of the parameter macro formal parameter list ;
When the number of user parameters exceeds the specified number of parameters , All the extra content will be driven by “__VA_ARGS__” Carried by ;
When the number of user parameters is exactly equal to the number of formal parameters ,"__VA_ARGS__" It's equivalent to an empty string
Look back at the previous question :
#define safe_atom_code(...)
And
#define safe_atom_code(__CODE)
The difference is , The former can include... In parentheses "," Almost anything inside ; The latter does not tolerate commas at all —— For example, you call a function , The parameters of the function need to be separated ? Another example , You used a comma expression ……—— It's sour to think about it .
Actually , One of the reasons for the initial birth of variable parameter list is to solve the problem of C Variable argument to function (va_args) The problem of cooperation , for example :
#define log_info(__STRING, ...) printf(__STRING, __VA_ARGS__)
therefore , When you use it , We can write this way :
log_info("------------------------------------\r\n");
log_info(" Cycle Count : %d", total_cycle_cnt);
When the macro is expanded, it actually corresponds to :
printf("------------------------------------\r\n",);
printf(" Cycle Count : %d", total_cycle_cnt);
There seems to be no problem , Did you notice a detail ? At the first printf() One more at the end of ",". Although some compilers , for example GCC I don't care about ( Maybe it's just a warning), But for Virgo programmers with serious cleanliness , How can this bear , So in ANSI-C99 When the standard introduces variable parameter macros , It's sweet again, and a less prominent grammar is added : When the following combination appears ",##__VA_ARGS__", If __VA_ARGS__ It's an empty string , Then the "," Will be deleted together . therefore , The above macro can be rewritten as :
#define log_info(__STRING, ...) printf(__STRING,##__VA_ARGS__)
here , The previous code will be expanded to :
printf("------------------------------------\r\n");
printf(" Cycle Count : %d", total_cycle_cnt);
Virgo means , You can sleep at ease this time .
If this is 99% Of C Programmers don't know "##" Hide usage , I'm so sorry for the audience , In fact, the positive film of this article has just begun .
3、 ... and 、 ## Operation
Comma expression , Friends who have been paying attention to the official account must be familiar with it. —— Previously reprinted articles 《【C Advanced 】 For listening and speaking “ Comma expression ” Just for the show ?》 It has been said in great detail , No more details here . In short , Is in the comma expression , The rightmost part of the comma will be the true return value of the expression .
Combined with the previous about ",##__VA_ARGS__" Introduction to usage , Do you realize that , In fact, the comma here can not only be the separator of the parameter list , It can also be the operator of comma expression . combination __VA_ARGS__ Characteristics of , We can write macros like this :
#define EXAMPLE(...) ( The default value is ,##__VA_ARGS__)
It has two uses :
1. When we use parameter macros, we don't fill anything in parentheses , It will eventually expand to the case where there are only default values :
EXAMPLE();
It's expanded into :
( The default value is )
2. When we provide any valid value , Will be expanded into a comma expression :
EXAMPLE( Value we provide );
It's expanded into :
( The default value is , Value we provide )
According to the characteristics of comma expression , here , The default value will be discarded ( Some compilers report invalid expressions warning, This is normal , Because the compiler noticed “ The default value is ” The expression represented is actually discarded , It thinks we've written a useless expression ).
This technique is actually right API The packaging is particularly effective : It allows us to simplify functions API Use , For example, when the user ignores , Automatically populate functions with some default values , When the user actively provides parameters , Override those defaults . Here I give two real examples :
(1) Provide default parameters for functions
Suppose we have an initialization function , The initialization function allows the user to configure some parameters through the structure :
typedef struct xxxx_cfg_t {
...
} xxxx_cfg_t;
int xxxx_init(xxxx_cfg_t *cfg_ptr);
In order to simplify the user's configuration process , The initialization function checks the pointer cfg_ptr Is it NULL, If NULL The default configuration is automatically used , Instead, the user-defined configuration will be used . here , We can provide default values through macros NULL:
#define XXXX_INIT(...) xxxx_init((NULL,##__VA_ARGS__))
(2) Provides default mask configuration for message processing
Some message processing functions can process a certain type of message in batches , Which message categories are selected , Is usually represented by a binary mask , for example :
typedef struct msg_t msg_t;
struct {
uint16_t msg;
uint16_t mask;
int (*handler)(msg_t *msg_ptr);
} msg_t;
At this point, we can build a set of syntax sugar with the help of macros :
#define def_msg_map(__name, ...) \
const msg_t __name[] = {__VA_ARGS__};
#define add_msg(__msg, __handler, ...) \
{ \
.msg = (__msg), \
.handler = &(__handler), \
.msk = (0xFFFF, ##__VA_ARGS__), \
}
Through macro add_msg We noticed that , When the user deliberately omits the setting msk when , Let's give the default value 0xFFFF—— This probably means , When processing messages , The message must be strictly matched before it can be handed over to the corresponding handler ; When the user specifies msk when , It may mean that a certain type of message is handed over to the same message processing function for processing . for example :
/*! \note The high byte indicates the type of operation :
such as 0x00 Represents the control class ,0x01 Express WRITE,0x02 Express READ
*/
enum {
SIGN_UP = 0x0001,
WRITE_MEM = 0x0100,
WRITE_SRAM = 0x0101,
WRITE_FLASH = 0x0102,
WRITE_EEPROM = 0x0103,
READ_MEM = 0x0200,
READ_SRAM = 0x0201,
READ_FLASH = 0x0202,
READ_EEPROM = 0x0203,
};
extern int iap_sign_up_handler(msg_t *msg_ptr);
extern int iap_write_mem(msg_t *msg_ptr);
extern int iap_read_mem(msg_t *msg_ptr);
def_msg_map( iap_message_map
/* Strict will SIGN_UP Mapping to In the corresponding processing function */
add_msg( SIGN_UP, iap_sign_up_handler ),
/* Batch process all WRITE operation , Use a mask to filter */
add_msg( WRITE_MEM, iap_write_mem, 0xFF00 ),
/* Batch process all READ operation , Use a mask to filter */
add_msg( READ_MEM, iap_read_mem, 0xFF00 ),
)
Four 、 Conclusion
Macros are not the devil that hinders code development and readability , The arrogance of being unfamiliar with knowledge is .
边栏推荐
- How to judge the advantages and disadvantages of low code products in the market?
- [Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 5
- Ml and NLP are still developing rapidly in 2021. Deepmind scientists recently summarized 15 bright research directions in the past year. Come and see which direction is suitable for your new pit
- Some summaries of the 21st postgraduate entrance examination 823 of network security major of Shanghai Jiaotong University and ideas on how to prepare for the 22nd postgraduate entrance examination pr
- The solution of permission denied
- Iframe to only show a certain part of the page
- Login operation (for user name and password)
- World document to picture
- Force buckle 142 Circular linked list II
- OSI seven layer reference model
猜你喜欢
LVS load balancing cluster deployment - Dr direct routing mode
French Data Protection Agency: using Google Analytics or violating gdpr
Servlet learning notes
netstat
It's hard to hear C language? Why don't you take a look at this (V) pointer
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 8
[Yunju entrepreneurial foundation notes] Chapter II entrepreneur test 13
Using terminal connection in different modes of virtual machine
The frost peel off the purple dragon scale, and the xiariba people will talk about database SQL optimization and the principle of indexing (primary / secondary / clustered / non clustered)
Detailed explanation of classic process synchronization problems
随机推荐
MYCAT middleware installation and use
DDS-YYDS
TCP slicing and PSH understanding
[directory] search
Classification and application of AI chips
MySQL performance optimization index
Process communication and thread explanation
How to create a new virtual machine
Possible to restore a backup of SQL Server 2014 on SQL Server 2012?
Ultimate bug finding method - two points
First knowledge of spark - 7000 words +15 diagrams, and learn the basic knowledge of spark
Awk getting started to proficient series - awk quick start
How to use "bottom logic" to see the cards in the world?
Data transmission in the network
Star leap plan | new projects are continuously being recruited! MSR Asia MSR Redmond joint research program invites you to apply!
Games101 Lesson 8 shading 2 Notes
The most robust financial products in 2022
Review of week 278 of leetcode II
03_ Armv8 instruction set introduction load and store instructions
Alibaba cloud server connection intranet operation