LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   What's this: __attribute__((packed)) (https://www.linuxquestions.org/questions/programming-9/whats-this-__attribute__-packed-193570/)

frankli 06-14-2004 08:46 PM

What's this: __attribute__((packed))
 
I see some code about Hostap project,in these codes,I found some structure which have such signs: __attribute__((packed)),I don't know what does this mean. So soon I found more such signs in Linux Kernel Souce code.Who can tell me what does this mean exactly and how I use it?Thanks

eric.r.turner 06-14-2004 09:59 PM

Here is how I think it works (please correct me if I'm wrong!)

__attribute__((packed)) ensures that structure fields align on one-byte boundaries. If you want to ensure that your structures have the same size on all processors, the packed attribute is how you tell gcc.

As an example, let's define this structure:

Code:

struct s {
  char aChar;
  int    anInt;
};

A processor that aligns on eight-byte boundaries may compile this so that aChar is in the first byte, followed by seven bytes of unused space, then starting anInt in the ninth byte.

A processor that aligns on four-byte boundaries may compile this so that aChar is in the first byte, followed by three bytes of unused space, then starting anInt in the fifth byte.

To force anInt to begin immediately after aChar, you would define the structure like this:

Code:

struct s {
  char aChar;
  int anInt __attribute__((packed));
};

To test these ideas out, I ran this code on an old Pentium 166:

Code:

#include <stdio.h>

struct s1 {
  char a;
  int  i;
};

struct s2 {
  char a;
  int i __attribute__((packed));
};

int main( int argc, char* argv[] ) {

  struct s1 s_1;
  struct s2 s_2;

  printf( "sizeof s1 is %d\n" , sizeof(s_1) );
  printf( "sizeof s2 is %d\n" , sizeof(s_2) );

  return( 0 );
}

And got these results:

Code:

eric.r.turner@turing:~/lab/packed$ ./foo
sizeof s1 is 8
sizeof s2 is 5

Looks like this processor aligns on four-byte boundaries.

frankli 06-14-2004 11:58 PM

thanks a lot!

frankli 06-15-2004 12:54 AM

But when I wirte the progarm like this:
struct s1 {
void *a;
char b[2];
int i;
};

struct s2 {
void *a
char b[2];
int i ;
}__attribute__((packed));

and got the result like this:
sizeof s1 is 12
sizeof s2 is 10
WHY? I think sizeof s2 should be 11!

Dark_Helmet 06-15-2004 01:56 AM

Why would it be 11?

void *a => 32-bit processor means this is 32 bits wide (or 4 bytes)
char b[2] => a char is typically 1 byte. You have two of them. So b occupies 2 bytes
int i => most 32-bit machines also default to 32 bits for plain integers (again, 4 bytes)

So sizeof(a) + sizeof(b) + sizeof(i) = 4 + 2 + 4 = 10

For your non-packed structure, you processor is aligning to 4-byte boundaries. Thus, a fills one full 4-byte block, b fills two bytes of the next block (leaving 2 other bytes unused), and i occupies the next full 4-byte block. So, in that case:

sizeof(a) + sizeof(b) + sizeof(wasted space) + sizeof(i) = 4 + 2 + 2 + 4 = 12

frankli 06-15-2004 03:20 AM

thanks,I made a mistake.

vijayviji 03-16-2011 02:50 AM

struct s2 {
char a;
int i __attribute__ ((packed));
char b;
int i1;
};

(on 32-bit machine)
Its showing the size of this structure is 12. Can you plz tell me why ?

vijayviji 03-16-2011 03:00 AM

Yup.. I found it..

Its allocating as follows,

1 byte + 4 bytes + 1 byte + 2 bytes + 4 bytes
char a, int i, char b, zeroes, int i1

eric.r.turner 03-16-2011 07:16 AM

Quote:

Originally Posted by vijayviji (Post 4292276)
Yup.. I found it..

LOL, this thread is nearly seven years old!

james strouth 03-16-2011 03:52 PM

I found this thread helpful. Thanks for the __attribute__ ((packed)) explaination.

rajesh180186 09-11-2012 01:52 AM

hi ,

struct s2 {
char a;
int i __attribute__ ((packed));
char b;
int i1;
};


here sizeof(s2) = 12.

But actually size should be 10 ( 1 byte+4 bytes + 1 byte + 4 bytes ),how ?

how it would be ( 1 byte+4 bytes + 1 byte + 2 bytes + 4 bytes ) =
sizeof(a)+ sizeof(i) +sizeof(b)+ 2 zeros + sizeof(i1))
here what is this another 2 bytes ( 2 zeros ) ? Can anyone ,please explain ?

Thanks in advance .

regards,
Rajesh.

NevemTeve 09-11-2012 02:47 AM

You might want to use two packed's:

Code:

struct s2 {
    char a;
    int i __attribute__ ((packed));
    char b;
    int i1 __attribute__ ((packed));
};

But please note that this packed stuff:

- is a non-standard extension
- slows down the processing
- should be avoided

eric.r.turner 09-11-2012 08:32 AM

Quote:

Originally Posted by rajesh180186 (Post 4777447)
hi ,

struct s2 {
char a;
int i __attribute__ ((packed));
char b;
int i1;
};


here sizeof(s2) = 12.

But actually size should be 10 ( 1 byte+4 bytes + 1 byte + 4 bytes ),how ?

how it would be ( 1 byte+4 bytes + 1 byte + 2 bytes + 4 bytes ) =
sizeof(a)+ sizeof(i) +sizeof(b)+ 2 zeros + sizeof(i1))
here what is this another 2 bytes ( 2 zeros ) ? Can anyone ,please explain ?

Thanks in advance .

regards,
Rajesh.

The processor is adding an extra two bytes after b so that the next integer starts on an 8 byte boundary. If you want the integer to start immediately after the char, you have to tell the processor to pack it.

NevemTeve 09-11-2012 09:03 AM

it's four, actually, not eight

rstewart 09-11-2012 09:37 AM

Why not use the pack pragma to set the alignment around the structure? IE:

Code:

#pragma pack(1)

struct s2 {
    char a;
    int i;
    char b;
    int i1;
};

#pragma pack()

sizeof(struct s2): 10

Whereas:

Code:


struct s2 {
    char a;
    int i;
    char b;
    int i1;
};

sizeof(struct s2): 16

johnsfine 09-11-2012 09:58 AM

Quote:

Originally Posted by rstewart (Post 4777728)
Why not use the pack pragma to set the alignment around the structure? IE:

I have seen some very convincing discussions by gcc experts on why #pragma is worse than __attribute__ for all the things that can be accomplished either way.

I don't remember the details well enough to repeat any of it convincingly, but I was convinced when I read it.

In real projects, it is a lot easier to wrap __attribute__ into a preprocessor macro (to make it properly conditional on the compiler/architecture in a semi portable project) than to do that with #pragma

Quote:

Originally Posted by rajesh180186 (Post 4777447)
struct s2 {
char a;
int i __attribute__ ((packed));
char b;
int i1;
};

I can't tell whether any of the answers to the reopening of this thread directly answer the question (vs. assume the answer). So my version of that answer is:

In the quoted code, the packed attribute applies only to i and not to i1
Other methods of specifying packed (appearing elsewhere in this thread) apply the packed attribute to the entire struct.

Quote:

Originally Posted by NevemTeve (Post 4777480)
But please note that this packed stuff:

- is a non-standard extension

That is important to understand when using it.

Quote:

- slows down the processing
That is only sometimes true at all and is rarely significant.

Quote:

- should be avoided
That claim should only be made about fundamentally flawed features, which this certainly is not. This is a very useful extension to C++, which should be used where appropriate. Like any other advanced language feature, it should not be scattered into your code without understanding or valid purpose. But that certainly doesn't mean it should be avoided.

theNbomr 09-13-2012 10:03 AM

Quote:

Originally Posted by NevemTeve (Post 4777480)
But please note that this packed stuff:
- should be avoided

I'd love to avoid it; it's a pain in the pants. What is your recommended alternative where data structures are part of a communications protocol that must be implemented in a consistent cross-platform manner?
--- rod.

NevemTeve 09-13-2012 10:27 AM

Code:

typedef struct network_format {
  char aChar;
  int8_t anInt [4]; /* determine byte-order */
} network_format;

typedef struct usable_format {
  char aChar;
  int32_t anInt;
} usable_format;

usable_from_network (usable_format *into, const network_format *from)
{
    into->aChar = from->aChar;
    into->anInt = big2hostl (*(int32_t *)from->anInt); /* pick */
    into->anInt = lit2hostl (*(int32_t *)from->anInt); /* one */
}

network_from_usable (network_format *into, const usable_format *from)
{
    into->aChar = from->aChar;
    *(int32_t *)into->anInt = host2bigl (from->anInt); /* pick */
    *(int32_t *)into->anInt = host2litl (from->anInt); /* one */
}


theNbomr 09-13-2012 12:35 PM

I agree that your suggestion will probably work with respect to packing/alignment (most of your suggestion seems to relate to byte-ordering; a different but related subject) on most architectures, there is nothing to ensure that the packing of the structure will necessarily be the same as a deliberately packed structure. Without the directive not to, padding bytes may be added in any part of the struct. In practice, AFAIK, this would rarely be done between char type elements, but again, this is not guaranteed. Nested structures make the problem even more difficult.
If the solution comes down to breaking every structure element into its respective char-sized elements, then I see the solution as much worse than the problem. I would say that the __attribute__((packed)) directive preserves the purpose of the C struct, by allowing an expression that plainly reflects the nature of the data. Unfortunately, it forces us to know when it is necessary, and embeds architecture-specific features into our source code.
--- rod.

NevemTeve 09-13-2012 11:08 PM

Sorry, from your answer I couldn't decide if my answer helped or not. Maybe I should summarize it in plain text: define a special structure only for the network traffic, in this structure every data-element that isn't aligned on its natural alignment (for elementary types it is an offset that is divisible with their size) are to be replaced with char-arrays. To convert from/to this special structure, you have to write conversion functions.

PS: The opposite problem may arise if the network protocol demands gaps between the fields that your compiler may or may not provide; you can add 'char unused_nnn [gapsize]' fields to be sure.

PPS: And obviously types short/int/long long mustn't be used in the network structure, int16_t/int32_t/int64_t are you friends.


All times are GMT -5. The time now is 07:10 AM.