I get the following unexpected results where I though the memory would be divided by 4 bytes only all the way but it isn’t:
602040 nes.val
602044 nex.c1
602045 nes.c2
602048 (nes.z).v1
60204c (nes.z).v2
602050 nes.str1
602057 nes.str2
The code is
/*
* 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() */
}
And the output I get is:
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)
-
What does it mean when the memory is not aligned by 4 bytes at a time? I thought that memory was always aligned in 4 bytes at a times.
-
Do I have any unused bytes between any part-variables? How do I inspect this?
Memory is not aligned, variables are. And the alignment requirements generally depend on the type of the variable itself.
For example,
charvariables may be able to go at any address, two-byteshortvariables may need to go at even addresses, four-byteintvariables may have to be aligned at four-byte boundaries and so on.C compilers are free to insert padding anywhere between members of a
struct(to align the members after that point) and following the last member (to assist aligning an array of thatstruct).They are not permitted to pad before the first member of a
struct.In terms of inspecting the padding, I’m not sure why you’d care since it’s not used for anything useful.
But, if you must, you can cast the address of the
structvariable to achar *and then access the individual bytes. Something like: