1

我得到了以下意想不到的结果,尽管内存将一直被 4 个字节除,但事实并非如此:

602040  nes.val
602044  nex.c1
602045  nes.c2
602048  (nes.z).v1
60204c  (nes.z).v2
602050  nes.str1
602057  nes.str2

代码是

/*
 * struct.c - Program to test struct
 * Written 2009-2012 by F Lundevall
 * Copyright abandoned. This file is in the public domain.
 */
#include <stdio.h>      /* Defines printf. */
#define ARRAYSIZE 3

/* Declare structured types (but not variables). */
struct ipair
{
  int v1;
  int v2;
};

struct nested
{
  int val;
  char c1;
  char c2;
  struct ipair z;
  char str1[7];
  char str2[11];
};

/* Declare global variable ipa - an array of struct ipair. */
struct ipair ipa[ ARRAYSIZE ]; /* Array of ipairs. */

/* Declare global variable na - an array of struct nested. */
struct nested na[ ARRAYSIZE ]; /* Array of ipairs. */

/* Declare some structured variables. */
struct ipair s1;
struct nested nes = { 17, 'Q', 'Z', { 117, 217 }, "Hello!", "Goodbye!" };

int main ()         /* Called as a method/function/subroutine. */
{
  int i;            /* Loop index variable. */
  int * ip;         /* Temporary pointer to int for printouts. */
  struct ipair * ipp;    /* Declare a pointer to struct ipair. */
  struct nested * nesp;  /* Declare a pointer to struct nested. */

  s1.v1 = 11;       /* Assign a value to val in s1. */
  s1.v2 = 17;       /* Assign a value to v2 in s1. */

  printf( "Message ST.01 from struct.c: Hello, structured World!\n");
  printf( "ST.02: s1: stored at %lx (hex), sizeof(s1) is %d (dec)\n",
          (unsigned long) &s1, (int) sizeof(s1) );
  printf( "ST.03: s1.v1 at %lx (hex) contains %d (dec), %x (hex)\n",
          (unsigned long) &(s1.v1), s1.v1, s1.v1);
  printf( "ST.04: s1.v2 at %lx (hex) contains %d (dec), %x (hex)\n",
          (unsigned long) &(s1.v2), s1.v2, s1.v2);

  ipp = &s1;        /* Pointer ipp now points to a struct ipair. */
  printf( "\nST.05: Executed ipp = &s1;\n");
  printf( "ST.06: ipp: stored at %lx (hex), contains %ld (dec), %lx (hex)\n",
          (unsigned long) &ipp, (unsigned long) ipp, (unsigned long) ipp );  
  printf( "ST.07: Dereference pointer ipp and we find: (*ipp).v1=%d, (*ipp).v2=%d\n",
          (*ipp).v1, (*ipp).v2 );
  printf( "ST.08: Dereference with different syntax: ipp->v1=%d, ipp->v2=%d\n",
          ipp->v1, ipp->v2 );

  (*ipp).v1 = nes.val; /* Copy a value using dot-syntax. */
  printf( "\nST.09: Executed (*ipp).v1 = nes.val;\n");

  ipp -> v2 = 4711;  /* Assign a value using arrow syntax. */
  printf( "ST.10: Executed ipp -> v2 = 4711;\n");
  printf( "ST.11: Dereference pointer ipp and we find: (*ipp).v1=%d, (*ipp).v2=%d\n",
          (*ipp).v1, (*ipp).v2 );

  for( i = 0; i < ARRAYSIZE; i += 1 )
  {
    ipa[ i ].v1 = 1000 + i;
    ipa[ i ].v2 = 2000 + i;
  }
  printf( "\nST.12: Initialized ipa.\n");

  ip = (int *) ipa;
  for( i = 0; i < ARRAYSIZE * 2; i += 1 )
  {
    printf("ST.%.2d: Memory at %lx (hex) contains %d\n",
           i+13, (unsigned long) ip, *ip);
    ip += 1;
  }

  ipp = ipa;
  printf( "\nST.23: Executed ipp = ipa;\n");
  printf( "ST.24: ipp: stored at %lx (hex), contains %ld (dec), %lx (hex)\n",
          (unsigned long) &ipp, (unsigned long) ipp, (unsigned long) ipp );  
  printf( "ST.25: Dereference pointer ipp and we find: ipp->v1=%d, ipp->v2=%d\n",
          ipp->v1, ipp->v2 );

  ipp = ipp + 1;
  printf( "\nST.26: Executed ipp = ipp + 1;\n");
  printf( "ST.27: ipp: stored at %lx (hex), contains %ld (dec), %lx (hex)\n",
          (unsigned long) &ipp, (unsigned long) ipp, (unsigned long) ipp );
  printf( "ST.28: Dereference pointer ipp and we find: ipp->v1=%d, ipp->v2=%d\n",
          ipp->v1, ipp->v2 );

  printf( "\nST.29: nes: stored at %lx (hex), sizeof(nes) is %d (dec)\n",
          (unsigned long) &nes, (int) sizeof(nes) );
  printf( "ST.30: nes.val at %lx (hex) contains %d (dec), %x (hex)\n",
          (unsigned long) &(nes.val), nes.val, nes.val);
  printf( "ST.31: nes.c1 at %lx (hex) contains '%c', %d (dec), %x (hex)\n",
          (unsigned long) &(nes.c1), nes.c1, nes.c1, nes.c1);
  printf( "ST.32: nes.c2 at %lx (hex) contains '%c', %d (dec), %x (hex)\n",
          (unsigned long) &(nes.c2), nes.c2, nes.c2, nes.c2);
  printf( "ST.33: nes.z: stored at %lx (hex)\n", (unsigned long) &(nes.z));
  printf( "ST.34: (nes.z).v1 at %lx (hex) contains %d (dec), %x (hex)\n",
          (unsigned long) &((nes.z).v1), (nes.z).v1, (nes.z).v1);
  printf( "ST.35: (nes.z).v2 at %lx (hex) contains %d (dec), %x (hex)\n",
          (unsigned long) &((nes.z).v2), (nes.z).v2, (nes.z).v2);
  printf( "ST.36: nes.str1 at %lx (hex) contains: %s\n",
          (unsigned long) &(nes.str1), nes.str1 );
  printf( "ST.37: nes.str2 at %lx (hex) contains: %s\n",
          (unsigned long) &(nes.str2), nes.str2 );

  na[0] = nes;     /* Copy the complete structure. */
  printf( "\nST.38: Executed na[0] = nes;\n" );

  nesp = na ;      /* Let nesp point to the copy. */
  printf( "\nST.39: Executed nesp = &na;\n" );
  printf( "ST.40: nesp: stored at %lx (hex); contains %ld (dec), %lx (hex)\n",
          (unsigned long) &nesp, (unsigned long) nesp, (unsigned long) nesp);
  printf( "ST.41: Dereference pointer nesp and we find: nesp->val=%d, and...\n",
          nesp->val );
  printf( "ST.42: nesp->c1='%c', (*nesp).c2='%c', and...\n",
      nesp->c1, (*nesp).c2 );
  printf( "ST.43: (nesp->z).v1=%d,(nesp->z).v2=%d, and...\n",
           (nesp->z).v1, (nesp->z).v2 );
  printf( "ST.44: nesp->str1=\"%s\" (*nesp).str2=\"%s\"\n",
      nesp->str1, (*nesp).str2 );

  nesp = nesp + 1;
  printf( "\nST.43: Executed nesp = nesp + 1;\n" );
  printf( "ST.44: nesp: stored at %lx (hex); contains %ld (dec), %lx (hex)\n",
          (unsigned long) &nesp, (unsigned long) nesp, (unsigned long) nesp);

  return( 0 );  /* exit from program by returning from main() */
}

我得到的输出是:

Message ST.01 from struct.c: Hello, structured World!
ST.02: s1: stored at 60212c (hex), sizeof(s1) is 8 (dec)
ST.03: s1.v1 at 60212c (hex) contains 11 (dec), b (hex)
ST.04: s1.v2 at 602130 (hex) contains 17 (dec), 11 (hex)

ST.05: Executed ipp = &s1;
ST.06: ipp: stored at 7fff9d23ca00 (hex), contains 6299948 (dec), 60212c (hex)
ST.07: Dereference pointer ipp and we find: (*ipp).v1=11, (*ipp).v2=17
ST.08: Dereference with different syntax: ipp->v1=11, ipp->v2=17

ST.09: Executed (*ipp).v1 = nes.val;
ST.10: Executed ipp -> v2 = 4711;
ST.11: Dereference pointer ipp and we find: (*ipp).v1=17, (*ipp).v2=4711

ST.12: Initialized ipa.
ST.13: Memory at 6020a0 (hex) contains 1000
ST.14: Memory at 6020a4 (hex) contains 2000
ST.15: Memory at 6020a8 (hex) contains 1001
ST.16: Memory at 6020ac (hex) contains 2001
ST.17: Memory at 6020b0 (hex) contains 1002
ST.18: Memory at 6020b4 (hex) contains 2002

ST.23: Executed ipp = ipa;
ST.24: ipp: stored at 7fff9d23ca00 (hex), contains 6299808 (dec), 6020a0 (hex)
ST.25: Dereference pointer ipp and we find: ipp->v1=1000, ipp->v2=2000

ST.26: Executed ipp = ipp + 1;
ST.27: ipp: stored at 7fff9d23ca00 (hex), contains 6299816 (dec), 6020a8 (hex)
ST.28: Dereference pointer ipp and we find: ipp->v1=1001, ipp->v2=2001

ST.29: nes: stored at 602040 (hex), sizeof(nes) is 36 (dec)
ST.30: nes.val at 602040 (hex) contains 17 (dec), 11 (hex)
ST.31: nes.c1 at 602044 (hex) contains 'Q', 81 (dec), 51 (hex)
ST.32: nes.c2 at 602045 (hex) contains 'Z', 90 (dec), 5a (hex)
ST.33: nes.z: stored at 602048 (hex)
ST.34: (nes.z).v1 at 602048 (hex) contains 117 (dec), 75 (hex)
ST.35: (nes.z).v2 at 60204c (hex) contains 217 (dec), d9 (hex)
ST.36: nes.str1 at 602050 (hex) contains: Hello!
ST.37: nes.str2 at 602057 (hex) contains: Goodbye!

ST.38: Executed na[0] = nes;

ST.39: Executed nesp = &na;
ST.40: nesp: stored at 7fff9d23ca08 (hex); contains 6299840 (dec), 6020c0 (hex)
ST.41: Dereference pointer nesp and we find: nesp->val=17, and...
ST.42: nesp->c1='Q', (*nesp).c2='Z', and...
ST.43: (nesp->z).v1=117,(nesp->z).v2=217, and...
ST.44: nesp->str1="Hello!" (*nesp).str2="Goodbye!"

ST.43: Executed nesp = nesp + 1;
ST.44: nesp: stored at 7fff9d23ca08 (hex); contains 6299876 (dec), 6020e4 (hex)
  1. 内存没有一次对齐 4 个字节是什么意思?我认为内存总是一次对齐 4 个字节。

  2. 任何部分变量之间是否有任何未使用的字节?我该如何检查这个?

4

1 回答 1

4

内存没有对齐,变量是。并且对齐要求通常取决于变量本身的类型。

例如,char变量可能能够到达任何地址,两字节short变量可能需要到达偶数地址,四字节int变量可能必须在四字节边界对齐等等。

C 编译器可以在 a 的成员之间的任意位置插入填充struct(以对齐该点之后的成员)和最后一个成员之后(以帮助对齐 that 的数组struct)。

他们不允许在 a 的第一个成员之前填充struct

在检查填充方面,我不确定您为什么会关心它,因为它没有用于任何有用的事情。

但是,如果必须,您可以将struct变量的地址转换为 a char *,然后访问各个字节。就像是:

struct xyzzy {
    char c;
    // 3 bytes padding if int alignment is 4
    int i;
};
struct xyzzy plugh;
char *twisty = (char *)(&plugh);
// Now use twisty[1] for the first padding byte and so on.
于 2012-10-16T08:10:04.503 回答