C ++结构对齐问题 [英] C++ struct alignment question

查看:166
本文介绍了C ++结构对齐问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个预定义的结构(实际上是几个),其中变量跨越32位字边界。在Linux(以及使用GCC的Windows)中,我可以使用'attribute((packed))'将我的结构打包到正确的大小。然而,我无法使用VC ++和#pragma pack以相同的方式工作。



使用GCC将返回正确的6字节大小:

  struct 
{
unsigned int a:3;
unsigned int b:1;
unsigned int c:15;
unsigned int troubleMaker:16;
unsigned short padding:13;
} __attribute __((packed))s;

使用VC ++会返回不正确的8字节大小

  #pragma pack(push)
#pragma pack(1)

struct
{
unsigned int a :3;
unsigned int b:1;
unsigned int c:15;
unsigned int troubleMaker:16;
unsigned short padding:13;
} s;

#pragma pack(pop)

我可以通过手动分割麻烦制造者,但我宁愿不要。任何想法?

解决方案

Crazy idea:首先写一个C99或C ++ 03-conforming程序






我建议不要使用供应商特定的C语言扩展来匹配设备或网络位格式。即使您使用一系列每个供应商的语言扩展来排列字段,您仍然需要担心字节顺序,并且您仍然有一个结构布局,需要额外的指令才能访问。



通过使用标准化的C API字符串和存储器复制函数以及Posix hton和ntoh函数,您可以编写符合C99标准的程序,该程序可以在任何架构或主机上以最高速度和高速缓存效率工作。

一个很好的做法是使用以下已发布标准的函数:

  c99:memcpy(),Posix:htonl(),htons(),ntohl(),ntohs()

更新:这里有一些代码应该在任何地方工作。您可能需要 < stdint.h> 来自这个项目,如果Microsoft 仍然没有为C99实现它,或者只是对通常的int大小假设进行设置。

  #include< stdlib.h> 
#include< stdint.h>
#include< string.h>
#include< stdio.h>
#include< arpa / inet.h>

struct packed_with_bit_fields {//仅用于比较
unsigned int a:3;
unsigned int b:1;
unsigned int c:15;
unsigned int troubleMaker:16;
unsigned short padding:13;
} __attribute __((packed)); //仅用于比较实现

struct unpacked {//这是示例结构
uint32_t a;
uint32_t b;
uint32_t c;
uint32_t troubleMaker;
}; // NOTE NOT PACKED

struct unpacked su;
struct packed_with_bit_fields sp;
char * bits =Lorem ipsum dolor;

int main(int ac,char ** av){
uint32_t x; //在这两种情况下字节顺序问题都被忽略

//这应该适用于任何环境和编译器
memcpy(& x,bits,4);
su.a = x& 7;
su.b = x>> 3& 1;
su.c = x>> 4& 0x7FFF的;
memcpy(& x,bits + 2,4);
su.troubleMaker = x>> 3& 0xFFFF的;

//此部分仅适用于gcc
memcpy(& sp,bits,6);
printf(sp.a == su.a
&& sp.b == su.b
&& sp.c == su.c
&& sp.troubleMaker == su.troubleMaker
?conforming and gcc implementation match \\\
:huh?\\\
);
返回0;
}


I have a predefined struct (actually several) where variables span across 32-bit word boundary. In Linux (and Windows using GCC) I am able to get my structs to pack to the correct size using 'attribute((packed))'. However I cannot get it to work the same way using VC++ and #pragma pack.

Using GCC this returns a correct size of 6 bytes:

struct
{
    unsigned int   a                : 3;
    unsigned int   b                : 1;
    unsigned int   c                : 15;
    unsigned int   troubleMaker     : 16;
    unsigned short padding          : 13;
} __attribute__((packed)) s;

Using VC++ this returns an incorrect size of 8 bytes

#pragma pack(push)
#pragma pack(1)

struct
{
    unsigned int   a                : 3;
    unsigned int   b                : 1;
    unsigned int   c                : 15;
    unsigned int   troubleMaker     : 16;
    unsigned short padding          : 13;
} s;

#pragma pack(pop)

I can get things to work by splitting 'troubleMaker' across the boundary manually but I'd prefer not to. Any ideas?

解决方案

Crazy idea: just write a C99 or C++03 -conforming program in the first place


I would suggest not using vendor-specific C language extensions to match device or network bit formats. Even if you get the fields to line up using a series of one-per-vendor language extensions, you still have byte order to worry about, and you still have a struct layout that requires extra instructions to access.

You can write a C99 conforming program that will work on any architecture or host and at maximum speed and cache efficiency by using the standardized C API string and memory copy functions and the Posix hton and ntoh functions.

A good practice is to use the following functions for which there exist published standards:

C99: memcpy(), Posix: htonl(), htons(), ntohl(), ntohs()

Update: here is some code that should work the same everywhere. You may need to get <stdint.h> from this project if Microsoft still hasn't implemented it for C99, or just make the usual assumptions about int sizes.

#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#include <arpa/inet.h>

struct packed_with_bit_fields {  // ONLY FOR COMPARISON
    unsigned int   a        : 3;
    unsigned int   b        : 1;
    unsigned int   c        : 15;
    unsigned int   troubleMaker : 16;
    unsigned short padding  : 13;
} __attribute__((packed));       // USED ONLY TO COMPARE IMPLEMENTATIONS

struct unpacked { // THIS IS THE EXAMPLE STRUCT
    uint32_t a;
    uint32_t b;
    uint32_t c;
    uint32_t troubleMaker;
}; // NOTE NOT PACKED

struct unpacked su;
struct packed_with_bit_fields sp;
char *bits = "Lorem ipsum dolor";

int main(int ac, char **av) {
  uint32_t x;   // byte order issues ignored in both cases

  // This should work with any environment and compiler
  memcpy(&x, bits, 4);
  su.a = x & 7;
  su.b = x >> 3 & 1;
  su.c = x >> 4 & 0x7fff;
  memcpy(&x, bits + 2, 4);
  su.troubleMaker = x >> 3 & 0xffff;

  // This section works only with gcc
  memcpy(&sp, bits, 6);
  printf( sp.a == su.a
      &&  sp.b == su.b
      &&  sp.c == su.c
      &&  sp.troubleMaker == su.troubleMaker
      ? "conforming and gcc implementations match\n" : "huh?\n");
  return 0;
}

这篇关于C ++结构对齐问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆