Gnu c Extension
Author: Tiger-John
Time: (modified again)
Mail: jibo.tiger@gmail.com
Blog: http://blog.csdn.net/tigerjb/article/details/8299557
Reprinted please indicate the source!
I. struct Value assignment:
1. assign values to members
For example, struct
struct st1 {int a;int b;int c;}
1.1 In {} format
struct st1 st1 = {1,2,3);
1.2 Linux kernel Style
struct st1 st1 = {.a = 1,.b = 2,.c =3,};
Note: This style (Add "." Before the member variable) can be assigned without assigning values in the order of the member variables. For example
struct st1 st1 = {.c = 3,.a = 1,.b = 2,};
2. assign a value to the whole.
struct st1 a, b;b = a;
3. assign values to another struct as the return value of the function.
struct st1 func1();struct st1 a = func1();
Inline
In C, inline modifiers are introduced to solve the problem of frequently called small functions that consume a lot of stack space or stack memory. Inline functions are defined using the inline keyword, and the function body and declaration must be combined. Otherwise, the compiler treats them as common functions. The inline function is generally placed in the header file.
Inline void function (int x); // It is just a declaration function and has no effect on inline void function (int x). // correct {return X ;}
Iii. typeof usage
1. the keyword typeof is used to obtain the data type of the expression.
(1) char * chptr;
Typeof (* chptr) ch; // equivalent to Char chtypeof (CH) * chptr1; // equivalent to char * chptr1typeof (chptr1) array [5]; // char * array [5] The data type of chptr1 is char *
(2) typeof is commonly used in Linux Kernel
#define min(x,y) ({ \ typeof(x) __min1 = (x); \ typeof(y) __min2 = (y); \ (void) (& __min1 == & __min2); \ __min1 < __min2 ? __min1 :min2})
Use typeof to obtain the data of X and Y, define two temporary variables, and assign the X and Y to the two temporary variables for comparison. In the macro definition, the (void) (& _ min1 = & __ min2) statement is used to warn that X and Y cannot belong to different data types.
Instance:
#include <stdio.h>#define min(x,y) ({ \ typeof(x) __min1 = (x); \ typeof(y) __min2 = (y); \ (void) (& __min1 == & __min2); \ __min1 < __min2 ? __min1 :min2})int main(){int a=4;int b=6; int min_data; min_data=min(a,b); printf(“the min=%d\n”,min_data); return 0;}
Execution result:
The min = 4
For example:
#include <stdio.h>#define min(x,y) ({ \ typeof(x) __min1 = (x); \ typeof(y) __min2 = (y); \ (void) (& __min1 == & __min2); \ __min1 < __min2 ? __min1 :min2})int main(){ int a=4; float b=6; int min_data; min_data=min(a,b); printf(“the min=%d\n”,min_data); return 0;}
The following warning is displayed:
Main. C: In function 'main ':
Main. C: 17: 9: Warning: Comparison of distinct pointer types lacks acast [enabled by default]
4. Compound statements in gnu c expressions
1. Preface:
In standard C, expressions refer to the combination of operators and operands, while compound statements refer to code blocks consisting of one or more statements enclosed in curly brackets. In standard C, composite statements cannot be used in expressions.
In gnu c, composite statements enclosed in parentheses are allowed to appear in an expression. The type of this expression is the type of the last substatement expression ending with a semicolon in a composite statement. Its value is also the value of the last subexpression.
Instance:
#include <stdio.h> main() { int a = ({ int b =4; int c =3; b+c; b+c-2; }); printf("a = %d\n",a); return 0; }
Output result:
Jibo @ Jibo-virtualbox :~ /Cv_work/work/gnuc/brace $./main
A = 5
Note:
The value of a is the value of the last statement in the composite statement, and its data type matches the Data Type of the last statement.
2. This feature is often used in the definition of Macros in Linux kernel.
#define min(x,y) ({ \ typeof(x) __min1 = (x); \ typeof(y) __min2 = (y); \ (void) (& __min1 == & __min2); \ __min1 < __min2 ? __min1 :min2})
A secure macro for minimum value is defined here. In Standard C, it is usually defined:
#define min(x,y) ((x) < (y) ? (x) : (y))
This definition calculates X and Y twice. When the parameter has side effects, incorrect results are generated. The statement expression is used to calculate the parameter only once, avoiding possible errors. Statement expressions are usually used for macro definition.
5. gnu c label elements
Standard C requires that the initial value of an array or structure variable must appear in a fixed order. In gnu c, the initialization value can appear in any order by specifying the index or structure domain name. The method for specifying an array index is to write '[Index] =' before the initialization value. to specify a range, use the format of '[first... last] =.
1. Application in array
You can use the [Index] = value form in the array initialization list to initialize a specified Element (specified by index.
Instance
#include <stdio.h>int main(void) { int i; int arr[6] = {[3] =10,11,[0]=5,6}; for (i=0;i<6;i++) printf("a[%d]=%d\n",i,arr[i]); return 0;}
The execution result is:
Jibo @ Jibo-virtualbox :~ /Cv_work/work/gnuc/initializer $./main
A [0] = 5
A [1] = 6
A [2] = 0
A [3] = 10
A [4] = 11
A [5] = 0
Note:
If a specified initialization project is followed by another value, for example, [3] =. Then these extra values are used to initialize subsequent array elements, that is, the value 11 is used to initialize arr [4].
For a C-language array, after one or more elements are initialized, uninitialized elements are automatically initialized to 0 and the latter is null (for pointer variables ). The values of all elements of an array without any initialization will be uncertain.
2. gnu c also supports "[first... Last] = value, that is, several elements in a range are initialized as the same value.
Instance
#include <stdio.h> int main() { int i; int arr[]={ [0 ... 3] =1,[4 ... 5]=2,[6 ... 9] =3}; for(i=0; i<sizeof(arr)/sizeof(arr[0]);i++ ) printf("arr[%d]:%d\n",i,arr[i]); return 0; }
The execution result is:
Jibo @ Jibo-virtualbox :~ /Cv_work/work/gnuc/initializer $./main1
Arr [0]: 1
Arr [1]: 1
Arr [2]: 1
Arr [3]: 1
Arr [4]: 2
Arr [5]: 2
Arr [6]: 3
Arr [7]: 3
Arr [8]: 3
Arr [9]: 3
Vi. Anonymous union or struct of GNU C
In gnu c, you can declare a consortium (or struct) in the struct without specifying its name, you can directly use members in a consortium (or consortium) Just like using struct members.
Instance:
#include <stdio.h> struct test_struct { char * name; union { char gender; int id; }; int num; }; int main(void) { struct test_struct test_struct={"jibo",'F',28}; printf("test_struct.gender=%c,test_struct.id=%d\n",test_struct.gende,test_sturct.id) return 0; }
The execution result is:
Jibo @ Jibo-virtualbox :~ /Cv_work/work/gnuc/non_struct $./main
Test_struct.gender = F, test_struct.id = 70
Note: anonymous union (or struct) is often used in Linux kernel ).
VII. Branch declaration of gnu c:
For the condition selection statement, GCC has a built-in command for optimization. When this condition often appears or is rarely used, the compiler can optimize the condition Branch selection based on this command. The kernel encapsulates this command into a macro, namely, likely () and unlikely ()
For example:
if (foo){/**/}
If you want to mark this option as a rare Branch:
if (unlikely(foo)){/**/}
Conversely, if you want to mark a branch as a true choice:
if(likely(foo)) {/**/}
Note: For details about likely () and unlikely (), see likely () and unlikely () in Linux kernel source code ()
8. Zero-length Array
In standard C, an array with a length of 0 is forbidden. The minimum length of an array must be 1 byte. However, GCC Allows defining zero-length arrays. So why does gnu c support a zero-length array? What are the advantages of it, how it is used, and where the zero-length array is mainly used:
(1) purpose: to save space and convenience when accessing an indefinite structure.
(2) usage: at the end of a struct, declare an array with a length of 0 to make the struct variable length. For the compiler, the array with a length of 0 does not occupy space, because the array name itself does not occupy space, and it is only an offset, the array name symbol itself represents an unchangeable address constant (note: the array name will never be a pointer !), However, we can dynamically allocate the size of this array.
Instance:
struct demo{ int a; char b[256]; char follow[0];};
Now you need to allocate a struct demo struct in the program and allocate the length of len bytes next to it. You can use the following method:
Structdemo * demo = (struct demo *) malloc (sizeof (struct demo) + Len );
In this way, you can use demo-> fellow to access the subsequent spatial data of the structure demo, which is very convenient. You can also use pointers to achieve this purpose.
struct demo{int a;char b[256];char *follow;};
Structdemo * demo = (struct demo *) malloc (sizeof (struct demo) + Len );
The zero-length array can also be achieved, but an extra char pointer is assigned. If you allocate additional data space, it will be a waste of space.
Note:
If a zero-length array similar to charbytes [0] is defined at the end of a structure, it indicates that the structure is not long and can be expanded by array. The structure must contain a length. The structure is similar to an information header. In addition, this structure can only allocate memory in heap mode.
Advantage: This method is more efficient than declaring a pointer variable in the struct and then dynamically allocating it. When accessing the array content, you do not need to access the content indirectly, avoiding two accesses.
Instance:
#include <stdio.h> #include <stdlib.h> struct test{ int count; //reverse is array name;the array is no item; //the array address follow test struct int reverse[0]; }; int main() { int i; struct test *ptest = (struct test *)malloc(sizeof(struct test)+sizeof(int)*10); for(i=0;i<10;i++){ ptest->reverse[i]=i+1; } for(i=0;i<10;i++){ printf("reverse[%d]=%d \n",i,ptest->reverse[i]); } printf("sizeof(struct test) =%d\n",sizeof(struct test)); int a = *(&ptest->count +1 ); printf("a=%d\n",a); return 0; }
The execution result is:
Jibo @ Jibo-virtualbox :~ /Cv_work/work/zeor_arry $./main
Reverse [0] = 1
Reverse [1] = 2
Reverse [2] = 3
Reverse [3] = 4
Reverse [4] = 5
Reverse [5] = 6
Reverse [6] = 7
Reverse [7] = 8
Reverse [8] = 9
Reverse [9] = 10
Sizeof (struct test) = 4
A = 1
Analysis:
We can see that the reverse array in the test struct does not occupy space. Sizeofstruct test occupies 4 memory space. The result body conunt variable is followed by a zero-length array.
9. Range mark
GCC also expands the range mark, which can represent a numerical range. This can be used in many places of the C program. The most common one is the switch/case statement.
Instance:
static int sd_major(int major_idx){switch (major_idx) {case 0:return SCSI_DISK0_MAJOR;case 1 ... 7:return SCSI_DISK1_MAJOR + major_idx - 1;case 8 ... 15:return SCSI_DISK8_MAJOR + major_idx - 8;default:BUG();return 0;/* shut up gcc */}}
Range flag can also be used to initialize some continuous elements in the array. For example, the array described in Chapter 5.
10. Specify attributes for functions, variables, and Data Types
Attributes are tools used by programmers to send information or commands to the compiler. They are usually used to command the compiler to complete some special processing during program compilation. Attributes can be specified on different types of objects, including functions, variables, and types. When specifying an attribute, you must use the keyword "_ attribute _" and then follow the attribute list enclosed by two parentheses. The attributes in the attribute list are separated by commas.
The usage is as follows:
__attrbitue__((attr_1,attr_2,attr_3))
1. noreturn
Function attribute. noreturn is used for functions, indicating that the function is never returned. This allows the compiler to generate slightly optimized code. The most important thing is to eliminate unnecessary warning information, such as uninitialized variables.
2. Format (archetype, string-index, first-to-check)
Function attribute. format is used for a function, indicating that the function uses printf, scanf, or strftime-style parameters. The most common mistake with this type of function is that the format string does not match the parameter, specifying the format attribute allows the compiler to check the parameter type based on the format string.
Parameter description:
1> "archetype" specifies the style;
2> "string-index" specifies the parameters of the Input Function to format the string.
3> "first-to-check" specifies the number of parameters of the function to be checked according to the preceding rules.
Instance:
include/linux/kernel.h asmlinkage int printk(const char * fmt, ...) __attribute__ ((format (printf, 1, 2)));
3. Unused:
Function attribute. the unused attribute is used for functions and variables, indicating that the function or variable may not be used. This attribute can prevent the compiler from generating warning information.
4. deprecated:
Function attribute. deprecated indicates that the function has been deprecated and should not be used again. If you try to use an obsolete function, you will receive a warning. You can also apply this attribute to types and variables to encourage developers to use them as little as possible.
5. Section ("section-name ")
The Section attribute in the function attribute __attribute _ puts the function or data in the input segment named "section_name" instead of the output segment.
Note:
In the Linux Driver Design, A _ init macro exists before the module loads the function, and the section attribute of attribute is also used.
# DEFINE _ init _ attribute _ (_ Section _ (". init. Text ")))
In the Linux kernel, all functions labeled as _ init are stored in the. init. Text Section during the link. In addition, all the _ init functions are in the Section. initcall. init also saves a function pointer. during initialization, the kernel will call these _ init functions through these function pointers and release the init section after initialization.
In the Linux kernel source code, segment-related important macro definitions include:
_ Init, _ initdata, _ exit, _ exitdata and similar macros
6. aligned (alignment)
Function: You can add _ attribut __when defining variables to determine whether to use memory alignment or whether the memory alignment is to several bytes.
Instance:
struct i387_fxsave_struct { unsigned short cwd; unsigned short swd; unsigned short twd; unsigned short fop; } __attribute__ ((aligned (16)));
It indicates that the variable of this structure type is 16 bytes aligned.
7. Packed:
Function attribute, which tells the compiler to cancel the optimization alignment of the structure during the compilation process and align it according to the actual number of bytes occupied.
8. Interrupt (""):
On the ARM platform, "_ attribute (Interrupt (" IRQ ")" indicates that the function is an interrupt handler.
11. Variable Parameter macros
In gnu c, macros can accept variable parameters, just like functions.
Instance:
include/linux/kernel.h#define pr_debug(fmt,arg...) \ printk(KERN_DEBUG fmt,##arg)
Note: Arg indicates the remaining parameters, which can be zero or multiple parameters. The parameters and the comma between them constitute the ARG value, replacing Arg during macro expansion.
For example:
pr_debug("%s:%d",filename,line)
Extended
printk("<7>" "%s:%d", filename, line)
The reason for using ## is that when processing Arg does not match any parameter, the ARG value is blank. In this case, the gnuc Preprocessor discards the comma before ##.
pr_debug("success!\n")
Extended
printk("<7>" "success!\n")
Note that there is no comma at the end.
12. built-in functions
Gnuc provides a large number of built-in functions, many of which are the built-in versions of Standard C library functions, such as memcpy, which have the same functions as the corresponding C library functions. There are other built-in functions whose names generally start with _ builtin.
1. _ builtin_return_address (level)
The built-in function _ builtin_return_address returns the return address of the current function or its caller. The level parameter specifies the number of search frameworks on the stack. 0 indicates the return address of the current function, 1 indicates the return address of the caller of the current function.
Instance:
kernel/sched.c printk(KERN_ERR "schedule_timeout: wrong timeout" "value %lx from %p\n", timeout, __builtin_return_address(0));
2. _ builtin_constant_p (exp)
The built-in function _ builtin_constant_p is used to determine whether a value is a compilation constant. If the exp value of the parameter is a constant, the function returns 1; otherwise, 0.
Instance:
include/asm-i386/bitops.h#define test_bit(nr,addr) \ (__builtin_constant_p(nr) ? \ constant_test_bit((nr),(addr)) : \ variable_test_bit((nr),(addr)))
Note: many computations or operations are more optimized when the parameter is a constant. In gnu c, the above method can be used to compile only the constant version or a very few version based on whether the parameter is a constant, in this way, it is both universal and can compile the optimal code when the parameter is a constant.
3. _ builtin_ct (exp, c)
The built-in function _ builtin_predict CT is used to provide branch prediction information for the compiler. Its return value is the value of the integer expression exp, and the value of C must be the compile time.
Instance:
include/linux/compiler.h#define likely(x) __builtin_expect((x),1)#define unlikely(x) __builtin_expect((x),0)kernel/sched.c if(unlikely(in_interrupt())) { printk("Scheduling in interrupt\n"); BUG(); }
The semantics of this built-in function is that the expected value of exp is C. The compiler can sort the order of statement blocks according to this information, so that the program can be executed more efficiently as expected. The above example indicates that the interruption context rarely occurs.