sizeof 运算符返回奇怪的结果

发布于 2024-12-04 09:04:23 字数 544 浏览 2 评论 0原文

语言是带有 gcc 编译器的 C,

如果我创建一个像这样的结构

struct test {

    char item_1[2];
    char item_3[4];
    char item_4[2];
    char item_5[2];
    char item_6[4];

};

,并且我执行 sizeof(struct test),它会返回 14(字节)。这是预期的结果。

但如果我执行

struct test {

    int16_t item_1;
    int32_t item_3;
    int16_t item_4;
    int16_t item_5;
    int32_t item_6;

};

sizeof(struct test) 将返回一些奇怪的内容,例如 44。当我使用 gnu ddd 进行调试时,我可以看到结构内部,并看到它看起来一切正常,并且所有项目都有预期的字节数。

那么为什么 sizeof 运算符返回一个意外的值呢?

language is C with gcc compiler

if i make a struct like so

struct test {

    char item_1[2];
    char item_3[4];
    char item_4[2];
    char item_5[2];
    char item_6[4];

};

and i do a sizeof(struct test) it returns 14(bytes). which is the expected result.

but if i do

struct test {

    int16_t item_1;
    int32_t item_3;
    int16_t item_4;
    int16_t item_5;
    int32_t item_6;

};

sizeof(struct test) will return something strange like 44. when i debug using gnu ddd i can see inside the structure and see that it all looks normal and all items have the expected number of bytes.

so why is the sizeof operator returning a unexpected value ?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

§对你不离不弃 2024-12-11 09:04:23

您混合了 32/16 位整数。

int16_t item_1[2]; // 2 * 2 = 4
int32_t item_3[4]; // 4 * 4 = 16
int16_t item_4[2]; // 2 * 2 = 4
int16_t item_5[2]; // 2 * 2 = 4
int32_t item_6[4]; // 4 * 4 = 16
                   // sum = 44

You have mixed 32/16 bit integers.

int16_t item_1[2]; // 2 * 2 = 4
int32_t item_3[4]; // 4 * 4 = 16
int16_t item_4[2]; // 2 * 2 = 4
int16_t item_5[2]; // 2 * 2 = 4
int32_t item_6[4]; // 4 * 4 = 16
                   // sum = 44
尘曦 2024-12-11 09:04:23

编译器可以在结构成员之间或最后一个成员之后插入填充。这样做通常是为了满足对齐要求。例如,int32_t 对象可能需要 4 字节对齐,因此编译器会在第一个和第二个成员之间插入 2 个字节的填充。详细信息将根据平台的不同而有所不同。

Compilers may insert padding between struct members, or after the last member. This is normally done to satisfy alignment requirements. For example, an int32_t object might require 4-byte alignment, so the compiler inserts 2 bytes of padding between the first and second members. The details will vary depending on the platform.

夜访吸血鬼 2024-12-11 09:04:23

编译器需要在结构成员之间插入填充,以使每个成员在其类型边界上对齐,并按写入方式对结构成员进行排序。如果对它们重新排序,使最大的成员位于结构定义的开头,它们将具有相同的大小。但由于您正在尝试使用 char 数组,我猜测您没有结构的原始定义,并且您正在尝试访问一些外部定义和创建的对象的字段。在这种情况下,我建议您要么获取正确的标头,要么使用 char[] 版本并将 char* 转换为它真正的类型。

compiler is required to insert padding between structure members to align each member on its type's boundary and to order the structure's members as written. If you reorder them such that the largest members are at the beginning of the structure definition, they will be the same size. But since you're trying it with arrays of char, I'm guessing you don't have the structure's original definition, and you're trying to access some externally defined and created object's fields. In that case, I suggest you either obtain the proper headers or use the char[] version and cast char* to whatever type it really is.

错爱 2024-12-11 09:04:23

对齐问题是因为现代 32 位 CPU 在 32 位地址边界上以 32 位字大小工作。如果 32 位边界上的 32 位字包含 2 个 16 位值,则这会导致需要额外的指令来获取正确的 16 位(即掩码和移位,以便剩下正确的 16 位) 。如果 32 位字被跨 32 位边界分割,则需要做更多的工作来检索它。

默认情况下,权衡是拥有更快的程序,而不是尽可能有效地使用内存。如果在使用结构成员的地方都需要额外的一对指令,那么这可能会比更紧密地包装结构节省的内存使用更多的内存,因此虽然一开始并不明显,但它是正确的选择。

如果您需要有效地存储结构(以性能为代价),那么“#pragma pack”允许您更紧密地打包成员,但它会导致程序更大、速度更慢。

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

http://www.cplusplus.com/forum/general/14659/

The alignment issue is because modern 32-bit CPU's work in 32-bit word sizes on 32-bit address boundaries. If a 32-bit word on a 32-bit boundary contains 2 16-bit values, this results in extra instructions being required to obtain the correct 16-bits (i.e. masking and shifting so that the correct 16-bits are all that remains). If a 32-bit word is split across a 32-bit boundary then there is even more work to do to retrieve it.

By default the trade-off is to have faster programs and not use the memory as efficiently as possible. If an extra couple of instructions are needed everywhere where a structure member is used then this will probably use more memory than tighter packing the structure saves so whilst not obvious at first it's the correct choice.

If you have a requirement to store structures efficiently (at a cost to performance) then "#pragma pack" allows you to tighter pack members, but it results in bigger slower programs.

http://gcc.gnu.org/onlinedocs/gcc/Structure_002dPacking-Pragmas.html

http://www.cplusplus.com/forum/general/14659/

记忆消瘦 2024-12-11 09:04:23
struct test {
    int16_t item_1[2]; // 2 * 16 +
    int32_t item_3[4]; // 4 * 32 +
    int16_t item_4[2]; // 2 * 16 +
    int16_t item_5[2]; // 2 * 16 +
    int32_t item_6[4]; // 4 * 32
                       // total = 352
}; 

352 位除以 8(8 位组成一个字节)是 44 个字节。

struct test {
    int16_t item_1[2]; // 2 * 16 +
    int32_t item_3[4]; // 4 * 32 +
    int16_t item_4[2]; // 2 * 16 +
    int16_t item_5[2]; // 2 * 16 +
    int32_t item_6[4]; // 4 * 32
                       // total = 352
}; 

352 bits divided by 8 (8 bits go into one byte) is 44 bytes.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文