结构在优化编译中的对齐问题 pragma(push, N) pragma(pop)

结构在优化编译中的对齐问题

Q: 我正在写一个流模块,其中用到了#pragma pack(),当使用

gcc -D_KERNEL -c abc.c
ld -r -o abc abc.o

编译链接时,一切正常。为了获得64-bit模块,我必须使用Sun Workshop 5.0,
结果导致系统崩溃。访问

http://docs.sun.com/htmlcoll/coll.32.8/iso-8859-1/CPPPG/Pragmas.html#15434

上面说必须在编译链接应用程序的时候指定"-misalign",所以我用了如下命令编译

/opt/SUNWspro/bin/cc -D_KERNEL -misalign -c abc.c
/usr/ccs/bin/ld -r -o abc abc.o

但是我不知道该如何在链接时指定"-misalign"。使用的是"/usr/ccs/bin/ld"。

A: Casper H.S. Dik - Network Security Engineer <Casper.Dik@Holland.Sun.Com>

"-misalign"仅仅用于应用程序,无法应用到内核编程中。"-misalign"使得编译
获得的代码增加了一些runtime glue,它们将指示内核模拟unaligned load(慢)。
作为内核编程,没有等效技术。

Q: 使用#pragma pack()是因为需要读取来自Windows客户端的报文,对端使用
#pragma pack(1)压缩了所使用的数据结构

#pragma pack(1)
typedef struct pkt_hdr_struct
{
uint8_t pkt_ver;
uint32_t pkt_type;
uint32_t pkt_len;
} pkt_hdr_t;
#pragma pack()

为了采用这个结构读取网络数据,Solaris端的服务程序需要强制转换匹配该结构,
但是一旦企图读取紧接在pkt_ver成员之后的pkt_type成员,崩溃了。尝试过其他
办法,首先用一个字符指针读取第一个字节,然后指针增一,把该指针强制类型
转换成( uint32_t * ),然后读取数据,依然崩溃。

此外,是否意味着无法在内核模块编程中使用#pragma pack()

A: Ed L Cashin <ecashin@coe.uga.edu>

我想你可以单独写一个pkt_header_read()函数,单字节读取然后拼装成相应的数
据类型。如果你想避免函数调用,可以使用"inline"关键字。

A: Casper H.S. Dik - Network Security Engineer <Casper.Dik@Holland.Sun.Com>

你是否意识到pkt_hdr_t结构使得你必须自己转换字节序(对端是x86平台)
我不认为#pragma pack()是最好的解决办法,考虑定义如下结构

struct phs
{
char ver;
char type[4];
char len[4];
}

采用memcpy()读取数据

memcpy( &phs.type[0], &pkt.pkt_type, 4 );

A: Andrew Gabriel <andrew@cucumber.demon.co.uk>

采用字符指针是正确的,但是你犯了个错误,编写如下函数

int read_misaligned_int ( int * iptr )
{
int i;
int value;
char * ptr = ( char * )iptr;
char * vptr = ( char * )&value;

for ( i = 0; i < sizeof( int ); i++ )
{
*vptr++ = *ptr++;
}

return( value );
}

此外,既然你提到对端是x86平台,可能还需要考虑字节序转换的问题

A: W. Richard Stevens <1999年逝世,享年49岁>

/*
* return value:
* 1 big-endian
* 2 little-endian
* 3 unknow
* 4 sizeof( short ) != 2
*/
static int byte_order ( void )
{
union
{
short s;
char c[ sizeof( short ) ];
} un;

un.s = 0x0201;
if ( 2 == sizeof( short ) )
{
if ( ( 2 == un.c[0] ) && ( 1 == un.c[1] ) )
{
puts( "big-endian" );
return( 1 );
}
else if ( ( 1 == un.c[0] ) && ( 2 == un.c[1] ) )
{
puts( "little-endian" );
return( 2 );
}
else
{
puts( "unknow" );
return( 3 );
}
}
else
{
puts( "sizeof( short ) = %d", sizeof( short ) );
return( 4 );
}
return( 3 );
} /* end of byte_order */

D: CERNET 华中地区网络中心 程序设计版 集体讨论汇总

为了解决Unix自定义结构在GCC优化编译中对齐问题,一般解决办法是用如下宏封装
自定义结构

#pragma pack(1)

struct my_arphdr
{
};

#pragma pack()

如果是SPARC/Solaris,还可以这样

struct my_arphdr
{
} __attribute__ ((packed));

两种办法其实都可以用在Unix系统/GCC编译器中。

D: mbuf@smth

关于结构中字节对齐问题,相应编译器选项为

GCC/G++ : -fpack-struct
Sun Workshop cc/CC: -misalign

最好不这样做,会大大降低程序效率,特别在某些架构中。应该尝试用位操作来处理。

D: Unknown@smth

GCC可以这么解决

#ifdef __GCC__
#define PACKED __attribute__((__packed__))
#else
#define PACKED
#endif

struct msg
{
u_int16_t PACKED first;
...
};

还是 VC 简单,#include 就搞定了

A: gfh_nuaa

DEC : #pragma pack(1)
SUN : #pragma pack(1)
AIX : 编译时 -q align=packed
HP-UX : #pragma pack 1

D: Joe Durusau

在 Visual C++ 中,使用 "-ZP1" 就可以让编译器对自定义结构进行单字节对齐,实
际就是取消了对齐优化。

A: law@apue.dhs.org 2001-12-20 13:09

1) 结构内部成员的pack

struct foo
{
char a;
int b __attribute__ ((packed));
};

2) 整个结构的pack

struct foo
{
char a;
int b;
}__attribute__ ((packed));

3) 文件范围的pack

#pragma pack(1)

struct foo
{
char a;
int b;
};

... ...

4) 编译选项的pack

-fpack-struct

但这是最危险的做法,因为这样做可能会使库函数和你的程序对结构内成员的偏移理
解不一致。

Q: 小四 <scz@nsfocus.com>

#pragma pack(push)
#pragma pack(n)
... ...
#pragma pack(pop)

push/pop这个用法都谁支持啊

A: law@apue.dhs.org

这个写法我没见过,VC和GCC都是这样写的

#pragma (push, N) // 把原来align设置压栈,并设新的pack为N
#pragma (pop) // align设置弹栈

8.6 如何得到非局部变量列表

Q: 什么工具可以从目标文件中提取非局部变量列表

A: Donald McLachlan <don@mars.dgrc.crc.ca>

最简单的就是nm,假设你有一个目标文件(或者已链接过的可执行文件),nm -g将显
示所有"全局"变量。下面是一个Solaris的例子:

--------------------------------------------------------------------------
/* gcc -o junk junk.c */

int var1;
static int var2;

int main ( void )
{
int var3;

return( 0 );
} /* end of main */
--------------------------------------------------------------------------

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/skyxie/archive/2007/08/30/1765875.aspx


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值