Page 1 of 1

Microsoft : The #pragma Preprocessing Directive - Part I Rate Topic: -----

#1 Martyn.Rae  Icon User is offline

  • The programming dinosaur
  • member icon

Reputation: 540
  • View blog
  • Posts: 1,406
  • Joined: 22-August 09

Posted 14 April 2011 - 01:07 AM

Microsoft : The #pragma Preprocessing Directive - Part I

Introduction

There have been a couple of tutorials posted here pertaining to the preprocessor directives available here at dream-in-code. In particular KYA's tutorial found here provides an excellent insight into the use of these directives.

This pair of tutorials concentrates on one of these directives, namely the #pragma directive. This directive provides the developer with very fine control of the code produced by the C/C++ compiler and it is this fine control we shall be concentrating on here.

The first tutorial looks at the power of the pack directive.

#pragma pack directive

This directive is used to control the packing of data into structures. Let's take a simple example:

    struct foo {
        char foo_char;
        short foo_short;
        long foo_int;
    };



Now, what size is that structure? Clearly, there is a byte for the char, two bytes for the short and four bytes for the long giving 1+2+4 = 7 bytes long. The correct answer is any one of the values 7, 8, 12, 24 and 48. Unless we know the packing value that is being applied to the structure, we have no idea other than one of the values already stated.

You see, the compiler can align each structure member on either a byte, two, four, eight or sixteen byte boundary.

So in reality if we had a packing of 8 bytes in force (which is the default), then the structure would actually look like this:

    struct foo {
        char foo_char;
        char foo_fill_1[7];
        short foo_short;
        char foo_fill_2[6];
        long foo_int;
    };



Where foo_fill_1 and foo_fill_2 are padded areas that have no name. This ensures that each member of the structure is aligned on a eight-byte boundary. That means that for a structure that contains seven useful bytes of information, 13 bytes are padded and not used!

To ensure that you have the correct padding, we use the #pragma pack(n) directive where n is the packing we require and may be a value of 1, 2, 4, 8 or 16. So, if we wanted our structure to be aligned on a byte boundary we would say:

#pragma pack(1)
    struct foo {
        char foo_char;
        short foo_short;
        long foo_int;
    };




Ah, but only if it were that simple! If you use the pack directive, you must remember to set back the original packing value which of course you don't have (this directive crosses include file boundaries). Enter the push and pop options.

#pragma pack(push) and #pragma pack(pop) directives

There are two variants of the #pragma pack directive where instead of a number you can use the keyword push or pop. The push actually pushes the current packing value on the compiler internal stack and the pop takes the current value on the stack an restores it as the current packing.

Using these aspects of the directive, we can now change the packing value to 1 safely, knowing that we have saved the current packing value and restored it back after we have finished using it.

#pragma pack(push)
#pragma pack(1)
    struct foo {
        char foo_char;
        short foo_short;
        long foo_int;
    };
#pragma pack(pop)



Conclusion

You have to be very careful using the pack directive, remembering to push and pop the current packing alignment before changing it. I have seen examples where a developer has not taken care in doing this on disc file record structures, and ended corrupting some very large files!

Part II of this tutorial may be found here.

This post has been edited by Martyn.Rae: 14 April 2011 - 12:03 PM


Is This A Good Question/Topic? 2
  • +

Page 1 of 1