2012-10-16 36 views
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

內存不對齊,變量是。對齊要求通常取決於變量本身的類型。

例如,char變量可能能夠去在任何地址,兩個字節short變量可能需要去偶地址,四字節int變量可能不得不在四字節邊界對齊等上。

C編譯器可以在struct(爲了對齊這些點之後的成員)和跟隨最後一個成員(幫助對齊該數組)的成員之間的任何位置插入填充。

他們不允許在struct的第一個成員之前填充。

在檢查填充方面,我不確定爲什麼你會在意,因爲它沒有用於任何有用的東西。

但是,如果你必須,,就可以把struct變量的地址到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.