Solved

alignment or struct alignment

Posted on 2004-09-06
25
755 Views
Last Modified: 2013-12-14
Hi,all:
Source code:
:::::::::::::::::::::::::::::::::::::::::
#include<stdio.h>

struct Name{
      char name[6];
};

void main()
{
      printf("%d\n",sizeof(struct Name));
}
:::::::::::::::::::::::::::::::::::::::::
The output is 6 ,but I expect that the output is 8.
Because I find the settings in my vc6.0,the struct member alignment is 8 bytes.
So, I think that the size of struct Name must be 8.
Is there something wrong with the concept???
Thanks a lot!
0
Comment
Question by:TKD
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 15
  • 10
25 Comments
 
LVL 15

Expert Comment

by:efn
ID: 11990765
The help file says:

"When you use the /Zp[n] option, where n is 1, 2, 4, 8, or 16, each structure member after the first is stored on byte boundaries that are either the alignment requirement of the field or the packing size (n), whichever is smaller."

Note the phrase "after the first."  When the structure has only one member, the compiler does not add padding.  It only adds padding between members.  So if you had another member after name, you would see some padding if the member's alignment requirement were greater than 2.  For example, with a second member of type int, the structure size would be 12 (6 + 2 + 4).

--efn
0
 

Author Comment

by:TKD
ID: 11990819
struct _TAG{
   char name[6];
   int num;
};
IF struct member alignment is 1
the sizeof(struct _TAG) is 10 ( 6 + 4).
IF struct member alignment is 2
the sizeof(struct _TAG) is 10 ( 6 + 4).
IF struct member alignment is 4
Because each field must be double word boundary,it adds two padding:
the sizeof(struct _TAG) is 10 ( 6 + 2 + 4).
IF struct member alignment is 8
Because each field's address must be multiple of 8,
the sizeof(struct _TAG) is 10 ( 6 + 2 + 4).
Right???
Thansk!
0
 

Author Comment

by:TKD
ID: 11990854
Oh....
:::::::::::::::::::::::::::::::::::::::::::::;;
#include<stdio.h>

struct Name{
      char ch;
      int num;
};

void main()
{
      struct Name n1;
      printf("%d\n",sizeof(struct Name));
      printf("%p\n",&n1.ch);
      printf("%p\n",&n1.num);
}
:::::::::::::::::::::::::::::::::::::::::::::::::::
The output is
8 <== size of struct Name
0012FF78 <== address of n1.ch
0012FF7C <== address of n1.num
The struct memory alignment is 8 bytes.
I expect that address of each field of struct Name must be multiple of 8.
But i find that the address of n1.num ISN'T multiple of 8.
Is there something wrong with the concept???
Thanks!
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 15

Expert Comment

by:efn
ID: 11990950
In the passage from the help file I quoted above, note the phrase "whichever is smaller."  This means that the structure alignment setting can only pack members more tightly than they otherwise would be packed--it will never add extra padding.  So, for example, if you have

struct s37
{
  char x[3];
  char y[5];
};

x and y only have to be on 1-byte boundaries, and even if you set the structure member alignment to 16, you won't get any padding.

Quoting the help file again:

"Every data object has an alignment-requirement. For structures, the requirement is the largest of its members."

In your second example, name has an alignment requirement of 1 and num has an alignment requirement of 4.  4 is larger than 1, so the alignment requirement of the structure is 4.  The structure's alignment requirement is determined only by the requirements of its members.  The member alignment setting of 8 only affects the amount of padding added.  It does not affect the alignment requirement for the structure.

--efn
0
 

Author Comment

by:TKD
ID: 11993352
source code:
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
#include<stdio.h>
struct Name{
      char ch;
      int num;
      double dnum;
};
union unName {
      char ch[5] ;
      int num ;
};
void main()
{
      struct Name n1;
      union unName n2;
      printf("%d\n",sizeof(struct Name));
      printf("%p\n",&n1.ch);
      printf("%p\n",&n1.num);
      printf("%p\n",&n1.dnum);

      printf("%d\n",sizeof(union unName));
      printf("%p\n",&n2.ch);
      printf("%p\n",&n2.num);

}
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
The output is:
16
0012FF70
0012FF74
0012FF78
8 <== size of union unName
0012FF68 <== address of n2.ch
0012FF68 <== address of n2.num
Why the sizeof(union unName) is 8???
Is there something about alignment???
I think that the sizeof(union Nmae) must be 5.
I am confused.
Thanks!
0
 
LVL 15

Expert Comment

by:efn
ID: 11993557
The C language standard only requires that the size of the union be large enough to hold its largest member, so in your example, it would have to be at least 5.  The standard also explicitly says that a compiler may add unnamed padding at the end of a structure or union.  So the compiler is allowed, but not required, to use a size of 8.  The only explanation I have for why it does so is that this was a decision of the people who implemented the compiler.  I don't know what their reasons were.

--efn
0
 

Author Comment

by:TKD
ID: 11993571
#define ALIGN_TYPE double
typedef union align_struct {
  struct {
      type1 field1;
      type2 filed2;
      type3 field3;
  } obj1;
 ALIGN_TYPE dummy;          /* included in union to ensure alignment */
};
I don't know what 's mean of ALIGN_TYPE.
Could you figure out ???
Thanks!!
0
 
LVL 15

Expert Comment

by:efn
ID: 11993619
"double" is a language keyword denoting a floating-point number type with more precision than "float."

In your example, "ALIGN_TYPE" is a macro that functions as another name for double.  The effect is the same as declaring the dummy member to be of type double.

--efn
0
 

Author Comment

by:TKD
ID: 11993663
I look codes from IJG JPEG Library:
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
/*
 * We allocate objects from "pools", where each pool is gotten with a single
 * request to jpeg_get_small() or jpeg_get_large().  There is no per-object
 * overhead within a pool, except for alignment padding.  Each pool has a
 * header with a link to the next pool of the same class.
 * Small and large pool headers are identical except that the latter's
 * link pointer must be FAR on 80x86 machines.
 * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
 * field.  This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
 * of the alignment requirement of ALIGN_TYPE.
 */
typedef union small_pool_struct {
  struct {
    small_pool_ptr next;     /* next in list of pools */
    size_t bytes_used;          /* how many bytes already used within pool */
    size_t bytes_left;          /* bytes still available in this pool */
  } hdr;
  ALIGN_TYPE dummy;          /* included in union to ensure alignment */
} small_pool_hdr;

/*
 * Many machines require storage alignment: longs must start on 4-byte
 * boundaries, doubles on 8-byte boundaries, etc.  On such machines, malloc()
 * always returns pointers that are multiples of the worst-case alignment
 * requirement, and we had better do so too.
 * There isn't any really portable way to determine the worst-case alignment
 * requirement.  This module assumes that the alignment requirement is
 * multiples of sizeof(ALIGN_TYPE).
 * By default, we define ALIGN_TYPE as double.  This is necessary on some
 * workstations (where doubles really do need 8-byte alignment) and will work
 * fine on nearly everything.  If your machine has lesser alignment needs,
 * you can save a few bytes by making ALIGN_TYPE smaller.
 * The only place I know of where this will NOT work is certain Macintosh
 * 680x0 compilers that define double as a 10-byte IEEE extended float.
 * Doing 10-byte alignment is counterproductive because longwords won't be
 * aligned well.  Put "#define ALIGN_TYPE long" in jconfig.h if you have
 * such a compiler.
 */

#ifndef ALIGN_TYPE          /* so can override from jconfig.h */
#define ALIGN_TYPE  double
#endif
::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
ALIGN_TYPE of purpose is to alignment.
But i don't know why??
0
 
LVL 15

Expert Comment

by:efn
ID: 11993783
The author of that code is using the dummy member for two purposes:  to control the size of the union, and to control its alignment.

I don't believe the standard requires a compiler to "make SIZEOF(small_pool_hdr) a multiple of the alignment requirement of ALIGN_TYPE."  However, if compilers do it anyway, the dummy member may have the desired effect.  I tested Microsoft Visual C++ 6.0 and it did behave that way.

Declaring a dummy double member of a union will serve to get objects of the union type aligned on addresses suitable for storing doubles.  It looks like these data structures may be used for storing various types of objects, so the library is following the example of the standard library function malloc and attempting to align objects for compatibility with the most data types.

For example, say the implementation has data types with 1-, 2-, 4-, and 8-byte alignment.  An address with 1-byte alignment may not be suitable for storing any object with other alignment, but an address with 8-byte alignment also automaticaly has 4-, 2-, and 1-byte alignment, so it can be used for any object, so 8-byte alignment is compatible with the most data types.  A double member typically gives you 8-byte alignment, so the double dummy member gives the union alignment so that it can store a wide variety of data types.

--efn
0
 

Author Comment

by:TKD
ID: 11993822
Oh...
I also don't know why compiler do it.
Is it ANSI standard???or depend on Compiler???
0
 
LVL 15

Expert Comment

by:efn
ID: 11993880
The alignment effect is standard.  The size-multiple effect is not standard, in my opinion, but may be the way compilers are typically implemented.
0
 

Author Comment

by:TKD
ID: 11993888
---------------------------------------------
>In your second example, name has an alignment requirement of 1 and num has an alignment requirement of 4.  4 is larger than 1, so the alignment requirement of the structure is 4.  The structure's alignment requirement is determined only by the requirements of its members.  The member alignment setting of 8 only affects the amount of padding added.  It does not affect the alignment requirement for the structure.
---------------------------------------------
So,no matter what you set the 'struct member alignment',the structure's alignment requirement is determined only by the requirement of its member.
IF 'struct member alignment' is 1 bytes,
struct Name{
      char ch;
      int num;
      double dnum;
};
ch has an alignment requirement of 1,num has an alignment requirement of 4,and dnum has an alignment requirement of 8.
Because alignment of 4 is more tightly than alignment of 8,the struct Name 's alignment is 4,not 8.
Right???
Thanks!
0
 

Author Comment

by:TKD
ID: 11993920
Maybe the compiler knows that the union contains an int.
The compiler will align's int's on double word boundary.
Is there anything about compiler how to implement???
Thanks!
0
 
LVL 15

Expert Comment

by:efn
ID: 11994078
> So,no matter what you set the 'struct member alignment',the structure's alignment requirement is determined only by the requirement of its member.

Right.

> Because alignment of 4 is more tightly than alignment of 8,the struct Name 's alignment is 4,not 8.
> Right???

No.  As I quoted before, "Every data object has an alignment-requirement. For structures, the requirement is the largest of its members."

In your example, 8 is the largest alignment requirement, so it is the requirement for the structure.

> Is there anything about compiler how to implement???

There are whole books about how to implement compilers.  For example:

Aho, Alfred V., Ravi Sethi, and Jeffrey D. Ullman.  Compilers:  Principles, Techniques, and Tools.  Addison-Wesley, 1986.

Parsons, Thomas W.  An Introduction to Compiler Construction.  W. H. Freeman, 1992.

--efn
0
 

Author Comment

by:TKD
ID: 11994851
Ok...
:::::::::::::::::::::::::::::::::
struct Name{
     char ch;
     int num;
};
:::::::::::::::::::::::::::::::::
The alignment of struct Name is 4.
So each member in struct Name must be double word boundary.
Right???
:::::::::::::::::::::::::::::::::
struct Name{
     char ch;
     int num;
     double dNum;
};
:::::::::::::::::::::::::::::::::
The alignment of struct Name is 8.
So address of  each member in struct Name must be multiple 8.
another concept:
Address of struct object must be multiple 8.
Address of num must be multiple 4,because its alignment is 4.
Address of dNum must be multiple 8,because its alignment is 8.
Which concept is right???
Thanks!
0
 

Author Comment

by:TKD
ID: 11997822
struct AlignStruct{
   char field1;
   short int field2;
   int field3;
   double field4;
};
field1 has an alignment of 1.
field2 has an alignment of 2.
field3 has an alignment of 4.
field4 has an alignment of 8.
The struct AlignStruct of alignment is 8.
address of field1 must be on multiple of 1.
address of field2 must be on multiple of 2.
address of field3 must be on multiple of 4.
address of field4 must be on multiple of 8.
Right???
0
 
LVL 15

Accepted Solution

by:
efn earned 80 total points
ID: 11998785
Yes, that's right, with the reservation that those numbers are typical of current implementations, not built into the language.  For example, if the hardware didn't care, a compiler writer might implement everything with alignment of 1, and that could still be a valid C compiler.  And in the past, ints were typically 16 bits, so they had alignment of 2.

--efn
0
 

Author Comment

by:TKD
ID: 12002420
Oh~I get it!
Thanks for you!
0
 

Author Comment

by:TKD
ID: 12002544
Oh...Sorry, I am a little probem.
::::::::::::::::::::::::::::::::::::::::::::::
#include<stdio.h>
#pragma pack(push,1)      
struct Student
{
      char sex;
      unsigned int age;
      double average;      
};
#pragma pack(pop)      

void main()
{
      struct Student s1;
      printf("%d\n",sizeof(struct Student));
}
::::::::::::::::::::::::::::::::::::::::::::::
The sizeof(struct Student) is 13(1+4+8).
--------------------------------------------------------------------
If I set the 'struct member alignment' to 1 bytes,
#include<stdio.h>
      
struct Student
{
      char sex;
      unsigned int age;
      double average;      
};
      
void main()
{
      struct Student s1;
      printf("%d\n",sizeof(struct Student));
}
The size of struct Student is 16.
---------------------------------------------
I think that
[#pragma pack(push,1)
...
#pragma pack(pop)]
is equalient to
[Set  'struct member alignment' to 1 bytes].
But why the results aren't the same.
WHY???
0
 
LVL 15

Expert Comment

by:efn
ID: 12002704
Did you get a warning like this?

warning C4653: compiler option 'structure packing (/Zp)' inconsistent with precompiled header; current command-line option ignored

I was able to reproduce your result, but I got this warning in the non-pragma case.  When I turned off using precompiled headers, the size went down to 13.

--efn
0
 

Author Comment

by:TKD
ID: 12002724
Yes,
"compiler option 'structure packing (/Zp)' inconsistent with precompiled header; current command-line option ignored"
What 's mean of above message???
How to turned off using precompiled headers???
And why  the size went down to 13 if turn off using precompiled headers??
Thanks!
0
 
LVL 15

Expert Comment

by:efn
ID: 12003207
Behind the scenes, the Visual Studio development environment runs the compiler from a command line.  When you change Project Settings through the graphical user interface, it changes the options specified on the command line.

It's not very well-documented, but apparently the structure packing setting is built into precompiled headers.  When you change the Struct member alignment setting to 1, Visual Studio plugs a "/Zp1" option into the command line.  Then when the compiler runs, it finds a disagreement between the command line option and the setting stored in the precompiled header file.  It can't do both, so it goes with the precompiled header setting and issues a warning to let you know that it is ignoring the /Zp1 command line option.

When you turn off precompiled headers, you eliminate the conflict, so the compiler obeys the command line option and uses 1-byte structure member alignments, so the size of the structure is 1 + 4 + 8 = 13, the same as when you set the structure member alignment to 1 with a #pragma pack directive in the source code.

To turn off precompiled headers, open the Project Settings, select the project in the list on the left side of the dialog box, select the C/C++ tab, and select Precompiled Headers in the Category list.  Then you can select the radio button for "Not using precompiled headers" and click OK.

--efn
0
 

Author Comment

by:TKD
ID: 12003272
How do we know the value of Struct member alignment in precompiled headers???
0
 

Author Comment

by:TKD
ID: 12003373
Why does Struct member alignment correlate to precompiled headers??
0

Featured Post

On Demand Webinar - Networking for the Cloud Era

This webinar discusses:
-Common barriers companies experience when moving to the cloud
-How SD-WAN changes the way we look at networks
-Best practices customers should employ moving forward with cloud migration
-What happens behind the scenes of SteelConnect’s one-click button

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

In our object-oriented world the class is a minimal unit, a brick for constructing our applications. It is an abstraction and we know well how to use it. In well-designed software we are not usually interested in knowing how objects look in memory. …
How to install Selenium IDE and loops for quick automated testing. Get Selenium IDE from http://seleniumhq.org Go to that link and select download selenium in the right hand columnThat will then direct you to their download page.From that page s…
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

733 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question