C language often makes people think that what they can express is very limited. It does not have advanced features such as Level 1 Functions and pattern matching. However, C is very simple and still has some very useful syntax skills and functions, but few people know it.
Specified Initialization
Many people know that static array Initialization is like this:
Intfibs [] = {1, 1, 2, 3, 5 };
The C99 standard actually supports a more intuitive and simple way to initialize various collection class data (such as struct, Consortium, and array ).
Array
We can specify the elements of the array for initialization. This is very useful, especially when we need to follow a set of # define to maintain a synchronous update of a ing relationship. Let's take a look at the definition of a group of error codes, such:
/* Entries may not correspond to actual numbers. Some entries omitted .*/
# Define EINVAL 1
# Define ENOMEM 2
# Define EFAULT 3
/*...*/
# Define E2BIG 7
# Define EBUSY 8
/*...*/
# Define ECHILD 12
/*...*/
Now, suppose we want to provide an error description string for each error code. To ensure the latest definition of the array, the syntax specified by this array can be used no matter whether the header file is modified or supplemented.
Char * err_strings [] = {
[0] = "Success ",
[EINVAL] = "Invalid argument ",
[ENOMEM] = "Not enough memory ",
[EFAULT] = "Bad address ",
/*...*/
[E2BIG] = "Argument list too long ",
[EBUSY] = "Device or resource busy ",
/*...*/
[ECHILD] = "No child processes"
/*...*/
};
In this way, sufficient space can be allocated statically, and the maximum index is valid. At the same time, the special index is initialized to the specified value, and the remaining index is initialized to 0.
Struct and Consortium
It is very useful to initialize data using the field names of struct and consortium. Suppose we define:
Structpoint {
Intx;
Inty;
Intz;
}
Then we initialize the structpoint as follows:
1
Structpoint p = {. x = 3,. y = 4,. z = 5 };
When we do not want to initialize all fields to 0, this method can easily generate struct during compilation without calling an initialization function. Www.2cto.com
For a consortium, we can use the same method, but we only need to initialize one field.
Macro list
A common method in C is to have a named object list. You need to create a function for each of them and initialize each of them, and extend their names in different code modules. This is often used in Mozilla source code. I learned this technique at that time. For example, in the project I worked for last summer, we had a macro list marked for each command. The method is as follows:
# Define FLAG_LIST (_)\
_ (InWorklist )\
_ (EmittedAtUses )\
_ (LoopInvariant )\
_ (Commutative )\
_ (Movable )\
_ (Lowered )\
_ (Guard)
It defines a FLAG_LIST macro. This macro has a parameter called _, which is itself a macro and can call every parameter in the list. A practical example may be used to illustrate the problem more intuitively. Suppose we have defined a macro DEFINE_FLAG, for example:
# Define DEFINE_FLAG (flag) flag,
EnumFlag {
None = 0,
FLAG_LIST (DEFINE_FLAG)
Total
};
# Undef DEFINE_FLAG
The following code can be obtained by extending FLAG_LIST (DEFINE_FLAG:
EnumFlag {
None = 0,
DEFINE_FLAG (InWorklist)
DEFINE_FLAG (EmittedAtUses)
DEFINE_FLAG (LoopInvariant)
DEFINE_FLAG (Commutative)
DEFINE_FLAG (Movable)
DEFINE_FLAG (Lowered)
DEFINE_FLAG (Guard)
Total
};
Then, extend the DEFINE_FLAG macro for each parameter, so that we can get the enum as follows:
EnumFlag {
None = 0,
InWorklist,
EmittedAtUses,
LoopInvariant,
Commutative,
Movable,
Lowered,
Guard,
Total
};
Next, we may need to define some access functions to better use the flag list:
# Define FLAG_ACCESSOR (flag )\
Boolis # flag () const {\
ReturnhasFlags (1 <flag );\
}\
Voidset # flag (){\
JS_ASSERT (! HasFlags (1 <flag ));\
SetFlags (1 <flag );\
}\
VoidsetNot # flag (){\
JS_ASSERT (hasFlags (1 <flag ));\
RemoveFlags (1 <flag );\
}
FLAG_LIST (FLAG_ACCESSOR)
# Undef FLAG_ACCESSOR
It is very enlightening to demonstrate the process step by step. If you are still confused about its use, you can spend some time on gcc-E.
Assertions during compilation
This is actually a very "creative" function implemented using the macro of C language. In some cases, especially during kernel programming, conditional checks can be performed during compilation, rather than during runtime, which is very useful. Unfortunately, the C99 standard does not support any assertions during compilation.
However, we can use preprocessing to generate code, which is compiled only when certain conditions are established (preferably a command that does not actually function ). There are various ways to do this, usually create an array or struct with negative size. The most common method is as follows:
/* Force a compilation error if condition is false, but also produce a result
* (Of value 0 and type size_t), so it can be used e.g. in a structure
* Initializer (or wherever else comma expressions aren't permitted ).*/
/* Linux callthese BUILD_BUG_ON_ZERO/_ NULL, which is rather misleading .*/
# Define STATIC_ZERO_ASSERT (condition) (sizeof (struct {int :-! (Condition );}))
# Define STATIC_NULL_ASSERT (condition) (void *) STATIC_ZERO_ASSERT (condition ))
/* Force a compilation error if condition is false */
# Define STATIC_ASSERT (condition) (void) STATIC_ZERO_ASSERT (condition ))
If (condition) is calculated as a non-zero value (that is, the true value in C), that is! (Condition) is zero, so the code can be compiled smoothly and generate a zero-size struct. If the (condition) result is 0 (true or false in C), a compilation error occurs when you try to generate a negative struct.
It is very simple to use. If any assumption condition can be statically checked, it can be asserted during compilation. For example, in the flag list mentioned above, the type of the Flag Set is uint32_t. Therefore, we can make the following assertions:
STATIC_ASSERT (Total <= 32)
It is extended:
(Void) sizeof (struct {int :-! (Total <= 32 )})
Now, assume Total <= 32. So -! (Total <= 32) equals 0, so this line of code is equivalent:
(Void) sizeof (struct {int: 0 })
This is a valid C code. Now we assume there are more than 32 logos, So -! (Total <= 32) is equal to-1, so the code is equivalent:
(Void) sizeof (struct {int:-1 })
Because the bit width is negative, it can be determined that if the number of flags exceeds the space we have assigned, the compilation will fail.
From Michael Xiao's program life