偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.
全部博文(1750)
分类: LINUX
2012-03-10 15:09:11
5. Extensions to the C Language Family
5.14 array of length zero
0长数组在GNU C中是允许的,0长数组的实现使得可变长数组的实现。
例如,
Struct line{
Int length;
Char contents[0];
};
对于32位处理器,sizeof(line)=4;
Struct line *thislne =(struct line *)malloc(sizeof(struct line)+this_length);
Thisline->length=this_length;
只多花销一个sizeof(int)的length,就可以实现变长数组
对数组的赋值通过thisline->contents[i]来实现
5.17 宏与可变数量的参数
在print系列中最多用到可变数量的参数(可以看va_list)
而在宏中#define debug(format,args,…) fprintf(stderr,format,args)
这里会出现一个问题,
如果调用debug(“A message”),对于后面没有参量的,则宏展开后会成为
Fprintf(stderr,”A message”,)这里会出现’,’,
为解决这个问题,会使用##
所以#define debug(format,args,…) fprintf(stderr,format,##args)
5.21 非初始化为常量
例如
Foo(float f,float g)
{
Float beat_freqs[2]={f-g,f+g};
/*…*/
}
5.23 designated initializers
关于指定初始化在驱动中经常用到,
有很多种用法,如
To specify an array index ,write ‘[index]= ‘ befroe the element value
int a[6]={[4]=29,[2]=15};
To initialize a range of elements to the same value,write ‘[first … last]=value’.
This is a GNU extension
int widths[]={[0 … 9]=1,[10 … 99]=2,[100]=3};
In a structure initializer,specify the name of a field to initialize with ‘.fieldname=’
Before the element value.
Struct point {int x,y};
Struct point p={
.y=yvalue;
.x=xvalue;
}
You can also use a designator when initializing a union ,to specify which element of the union should be used.
Union foo{ int i;double d;};
Union foo f={.d=4};
5.24 case ranges
制定一个case 范围
Case low … high
注意: case 1 … 5 而不能写成 case 1…5 否则会有语法错误
5.26 mixed declarations and code
Int i;
/*…*/
i++;
int j=i+2;
5.27 declaring attributes of functions
In GNU C,you declare certain things about functions called in your program which help the complier optimize function calls and check you code more carefully.
Keyword __attribute__
Alias(“target”) 对函数的另一个申明
Void __f () {/*do something*/}
Void f() __attribute__ ((weak,alias(“__f”)));
f是对__f的弱申明
aligned(alignment)
alloc_size
always_inline
dllimport dllexport
deprecated
dllexport __declspec(dllexport) __attribute((dllexport))
dllimport
interrupt void f() __attribute__ ((interrupt(“IRQ”)));
noinline asm(“”)
section(“section-name”)
extern void foobar (void) __attribute__ ((section(“bar”)));
用于制定函数所在的段
packed __attribute__ ((packed)) packed属性用来申明尽量最小字节的对齐
5.34 specifying attribute of variables
i386 variable attribute
handling of zero-length bitfields
(1)
If a zero-length bitfields is inserted between two bitfields that would normally be coalesced, the bitfields will not be coalesced.
Example:
Struct
{
Ulong bf_1: 12;
Ulong :0;
Ulong bf_2:12;
}t1;
有0长的bitfield插入,sizeof(t1)=8 bytes
如果没有0长bitfield,则sizeof(t1)会是4bytes
(2)
If a zero-length bitfield is inserted after a bitfield, foo, and the alignment
of the zero-length bitfield is greater than the member that follows it, bar,
bar will be aligned as the type of the zero-length bitfield.
For example:
struct
{
char foo : 4;
short : 0;
char bar;
} t2;
struct
{
char foo : 4;
short : 0;
double bar;
} t3;
For t2, bar will be placed at offset 2, rather than offset 1. Accordingly,
the size of t2 will be 4. For t3, the zero-length bitfield will not affect the
alignment of bar or, as a result, the size of the structure.
Taking this into account, it is important to note the following:
1. If a zero-length bitfield follows a normal bitfield, the type of the zerolength
bitfield may affect the alignment of the structure as whole. For
example, t2 has a size of 4 bytes, since the zero-length bitfield follows
a normal bitfield, and is of type short.
2. Even if a zero-length bitfield is not followed by a normal bitfield, it
may still affect the alignment of the structure:
struct
{
char foo : 6;
long : 0;
} t4;
Here, t4 will take up 4 bytes.
3. Zero-length bitfields following non-bitfield members are ignored:
struct
{
char foo;
long : 0;
char bar;
} t5;
Here, t5 will take up 2 bytes.
5.55 二进制前缀0b定义二进制变量
The following statements are identical:
i=42;
i=0x2a;
i=052;
i=0b10101000;
5.46 第五章还提到offsetof,这里举驱动中经常用到container_of为例分析(list_entry)通过结构中的某个变量获取结构本身的指针
Container_of ---cast a member of a structrue out to the containg structure
@ptr : the pointer to the member
@ type: the type of the container struct this is embeded in
@member: the name of the member within the struct
#define container_of (ptr,type,member)({/
Const typeof(((type*)0)->member)*__mptr=(prt);/
(type *)((char *)__mptr-offsetof(type,member));})
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
首先offsetof得到member在struct中的偏移量,(type*)0->member是强制将结构指针设置为0地址的结构指针
__mptr是结构中member的指针,通过(char *)指针减去偏移量就得到所需结构的指针(当然需要指针转换)
之所以要强制转换成(char *)指针是因为不能保证member的类型,如果非(char *)指针,在偏移上会出现sizeof(member类型)*offsetof(type,member)的偏移
前段时间上网看到一个帖子,说是在结构中如果有0长数组的时候,offsetof的获取会出现问题,这个本身也是由于0长数组决定的,需要在使用的时候注意。
例如,
#include"stdio.h"
#define offsetof(TYPE,MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#define container_of(ptr,type,member) ({/
typeof(((type *)0)->member)* __mptr=(ptr);/
(type *)( (char *)__mptr-offsetof(type,member));})
struct test
{
char h[10]; //这里设置10而不设置12是为了0长数组和4字节对齐
char hhh[0];??
int m;
}hello={"222",1,0x11};
int main(int argc,char **argv)
{
struct test *hello_temp=container_of(&hello.m,struct test,m);
for(int i=0;i<16;i++)
printf("%x ",*((char *)hello_temp+i));
return 0;
}
hhh[0]是占指针,但是无数据的,定义hello{“222”,1,0x11},结果正确,
如果hello={“222”,0x11} 此时0x11是赋给hhh[0],虽然在结构上此值不赋给对应的地址,但是也不会赋值给变量m,所以定义此类结构,需要填充对应的空数据。
事实上我觉得这样定义结构是不合理的,gcc定义0长数组是为了实现变长数组,故最好将0长数组放置于结构尾。