Solved

alignment or struct alignment

Posted on 2004-09-06
25
752 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
  • 15
  • 10
25 Comments
 
LVL 15

Expert Comment

by:efn
Comment Utility
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
Comment Utility
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
Comment Utility
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
 
LVL 15

Expert Comment

by:efn
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
#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
Comment Utility
"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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:TKD
Comment Utility
---------------------------------------------
>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
Comment Utility
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
Comment Utility
> 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Oh~I get it!
Thanks for you!
0
 

Author Comment

by:TKD
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
How do we know the value of Struct member alignment in precompiled headers???
0
 

Author Comment

by:TKD
Comment Utility
Why does Struct member alignment correlate to precompiled headers??
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Jaspersoft Studio is a plugin for Eclipse that lets you create reports from a datasource.  In this article, we'll go over creating a report from a default template and setting up a datasource that connects to your database.
Windows programmers of the C/C++ variety, how many of you realise that since Window 9x Microsoft has been lying to you about what constitutes Unicode (http://en.wikipedia.org/wiki/Unicode)? They will have you believe that Unicode requires you to use…
The goal of this video is to provide viewers with basic examples to understand how to create, access, and change arrays in the C programming language.
This tutorial covers a step-by-step guide to install VisualVM launcher in eclipse.

772 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

Need Help in Real-Time?

Connect with top rated Experts

12 Experts available now in Live!

Get 1:1 Help Now