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

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

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 <pshpack1.h> 就搞定了

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 */
-------------------------------------------------------------------------- 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值