c++ - 打包或不打包仅包含数组的结构

标签 c++ c arrays gcc buffer

实验: 让我们在 c/c++ 中声明一个 SHA-512 摘要的容器(使用 GCC):

#define DIGEST_LENGTH 512
struct Digest {
  uint32_t bits[DIGEST_LENGTH / 8 / sizeof(uint32_t)];
} __attribute__((packed));

让我们不要争论选择 uint32_t 数组而不是 char 数组。顺其自然。

然后我们可以按如下所示的方式从工作缓冲区中读入摘要:

Digest digest;
......
memcpy(&digest, buffer, sizeof(Digest));

类似地,我们可以将摘要写入工作缓冲区:

memcpy(buffer, &digest, sizeof(Digest)); //Assuming sufficient buffer size

我的问题:

一个。 packed 属性是否是 sizeof(Digest) 始终返回正确大小(= 512 位或 64 字节)的充分必要条件?

B. digest->bits[i] 在我们保留 packed 属性的同时在所有架构上都是安全的操作吗?

C.我们能否在保持容器不透明的同时简化表示?

D.如果我们保留表示,是否需要支付运行时惩罚?

我知道还有其他关于 packed 属性的问题,但我的问题专门针对包含单个基本类型数组的结构。

最佳答案

A. Is the packed attribute necessary and sufficient condition for sizeof(Digest) to always return the correct size (= 512 bits or 64 bytes)?

足够了。

B. Is digest->bits[i] a safe operation on all architectures while we keep the packed attribute?

我认为您不理解__attribute__((packed))。以下是实际执行的操作。

When packed is used in a structure declaration, it will compress its fields such, such that, sizeof(structure) == sizeof(first_member) + ... + sizeof(last_member).

这里是上面语句的资源的url Effects of __attribute__((packed)) on nested array of structures?

编辑:

当然是安全的。打包定义内存中的布局,但不要担心,因为访问特定数据类型由编译器处理,即使数据未对齐也是如此。

C. Can we simplify the representation while keeping the container opaque?

是的,您可以只定义一个简单的缓冲区 uint32_t bits[LENGTH];,它将以同样的方式为您工作。

D. Is there a run-time penalty to pay if we keep the representation?

一般来说是的。打包强制编译器不在成员之间的数据结构中执行填充。数据结构中的填充使物理对象更大,但对奇异字段的访问更快,因为它只是读取操作,不需要读取、掩码和旋转等。

请查看下面这个非常简单的程序,它显示了打包对结构大小的影响。

#include <stdio.h>
#include <stdint.h>

#pragma pack(push, 1) 
typedef struct _aaa_t {
  uint16_t a;
  uint8_t b;
  uint8_t c;
  uint8_t d;
} aaa_t;
#pragma pack(pop)

typedef struct _bbb_t {
  uint16_t a;
  uint8_t b;
  uint8_t c;
  uint8_t d;
} bbb_t;

int main(void) {
    aaa_t a;
    bbb_t b;
    printf("%d\n", sizeof(a));
    printf("%d\n", sizeof(b));
    printf("%p\n", &(a.a));
    printf("%p\n", &(a.b));
    printf("%p\n", &(a.c));
    printf("%p\n", &(a.d));
    printf("%p\n", &(b.a));
    printf("%p\n", &(b.b));
    printf("%p\n", &(b.c));
    printf("%p\n", &(b.d));
    return 0;
}

程序输出:

5
6
0xbf9ea115
0xbf9ea117
0xbf9ea118
0xbf9ea119
0xbf9ea11a
0xbf9ea11c
0xbf9ea11d
0xbf9ea11e

解释:

Packed:
     ____________ _______ _______ _______ _______
    |            |       |       |       |       |
    | 0xbf9ea115 | msb_a | lsb_a | lsb_b | lsb_c |
    |____________|_______|_______|_______|_______|
    |            |       |
    | 0xbf9ea119 | lsb_d |
    |____________|_______|

Not Packed:
     ____________ _______ _______ _______ _______
    |            |       |       |       |       |
    | 0xbf9ea11a | msb_a | lsb_a | lsb_b | lsb_c |
    |____________|_______|_______|_______|_______|
    |            |       |       |
    | 0xbf9ea11e | lsb_c |  pad  |
    |____________|_______|_______|

编译器这样做是为了生成比没有填充和内存对齐优化的代码更快地访问数据类型的代码。

您可以在此链接下运行我的代码demo program

关于c++ - 打包或不打包仅包含数组的结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32055032/

相关文章:

java - 在 Java 中将 png 文件作为二维整数数组输入

java - 计算元素在数组中出现的次数 - Java

php - 在MySQL中解析多维json字符串

c++ - boost::read_graphml Visual Studio 2013

c - 将多维数组传递给函数 C

c++ - Clang 中的嵌套 C 数组结构对齐

c - 使用 ANTLR C 目标,如何使用操作来打印 token ?

c - 如何从存储的字符串数组中使用 getchar() 函数?

c++ - 函数名 __func__ 的预定义宏

c++ - 显示实现最大利润的步骤