【问题标题】:Why can't we access bits that we pad in structures?为什么我们不能访问我们在结构中填充的位?
【发布时间】:2016-05-03 06:37:29
【问题描述】:

我的问题是我们使用填充来对齐结构。

typedef struct structb_tag
{
   char c;
   int  i;
} structb_t;

这里我们使用 8 个字节。为什么我们不能使用那么多的 3 个字节?

【问题讨论】:

  • 您选择不在那里粘贴任何字段。如果你想使用这些字节,你应该以不同的方式定义你的结构。
  • 你会怎么称呼他们?它们没有名字——不同的编译器可以使用不同数量的填充。
  • 你可以,使用指针。
  • @LP:但你不应该这样做。
  • @alk 是的,当然。 ;)

标签: c linux struct padding


【解决方案1】:

为什么我们不能使用 3 个字节

你可以。

为此,请测量您的实现为struct 分配的大小,然后将其添加为一个与所测量大小完全相同的字符数组的联合,然后就可以了。

假设这个

typedef struct structb_tag
{
   char c;
   int i;
} structb_t;

使用 8 个字节创建,即 sizeof (structb_t) 计算结果为 8,将其更改为以下内容

typedef union unionb_tag
{
  char bytes[8];
  struct
  {
    char c;
    int i;
  } structb;
}

就可移植性和稳健性而言,更可靠的是:

typedef union unionb_tag
{
  struct structb_tag
  {
    char c;
    int i;
  } structb;
  char bytes[sizeof (struct structb_tag)];
}

【讨论】:

  • 你可以定义一个struct标签(structb_tag),将bytes数组声明移到struct def后面声明为char bytes[sizeof(struct structb_tag)];
  • @LPs:我刚刚开始提出这个建议...:)
  • 当您对联合的结构部分执行任何操作时,填充值是否会变得不确定?
  • @user2357112:正确,您不想在写信之前阅读它们...... - 像往常一样。
【解决方案2】:

如果您使用的是 GCC,并且空间对您来说是最重要的,而不是速度(填充提供),您可以要求编译器不要进行填充,struct __attribute__((__packed__)) mystruct,填充是编译器对齐结构的方式在自然中以更快地访问。

【讨论】:

    【解决方案3】:

    您始终可以将指向结构的指针转换为字节指针并访问该结构的任何字节。

    不过,这种方式很危险。

    【讨论】:

      【解决方案4】:

      填充是依赖于实现的,标准没有定义,你不能不使用它们,因为没有办法引用填充字节。

      【讨论】:

        【解决方案5】:

        是的,你可以。

        typedef struct structb_tag
        {
           char        c;
           char        pad[3];
           int         i;
        } structb_t;
        
        structb_t test;
        test.pad[0] = 'a';
        

        【讨论】:

          【解决方案6】:

          简而言之,我们可以使用那三个字节。

          我们之所以需要 3 个字节的填充是为了优化内存使用,所以编译器会帮我们在 c 和 i 之间添加一个间隙。所以当你使用

          typedef struct structb_tag
          {
             char        c;
             int         i;
          } structb_t;
          

          其实

          typedef struct structb_tag
          {
             char        c;
             char[3]     unseen_members;
             int         i;
          } structb_t;
          

          访问这些看不见的成员不会导致任何分段错误。从操作系统的角度来看,访问程序员显式声明的成员和编译器隐式声明的成员没有区别。

          #include <stdio.h>
          #include <string.h>
          
          
          typedef struct Test {
              char c;
              int i;
          } MyTest;
          
          int main() {
              MyTest my_test;
              memset(&my_test, 0, sizeof(my_test)); 
          
              my_test.c = 1;
              int* int_ptr = (int *)&my_test.c; 
          
              printf("Size of my_test is %lu\n", sizeof(my_test));
              printf("Value of my_test.c(char) is %d\n", my_test.c);
              printf("Value of my_test.c(int) is %d\n", *int_ptr);
              return 0;
          }
          

          这给出了:

          Size of my_test is 8
          Value of my_test.c(char) is 1
          Value of my_test.c(int) is 1
          

          【讨论】:

            【解决方案7】:

            我们可以使用指向该结构的指针访问结构中的任何字节,并将该指针类型转换为 (char *),如果我们相应地增加该指针,那么我们可以访问任何字节,但这不是很好的编程技巧。结构用一些额外的字节填充,以便程序的执行可以变得更快。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2010-09-18
              • 1970-01-01
              • 1970-01-01
              • 2013-04-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多