pragma pack(1) on struct contains object

S

Steven Woody

In our project, one used the following struct

#pragma pack(1)
struct Foo {
uint8_t b1;
uint8_t b2;
uint8_t b3;
std::vector<uint8_t> buf;
...
};
#pragma pack()

this work on PC, but not on ARM target using a gcc/g++ cross
compiler. The problem is, on ARM, after defined a variable of Foo
and want to access a method of buf, such as

Foo foo;
foo.buf.resize(100);

the program will exit. I guss it's a segment failure.


Can you experts explain for me the reason? I know, it is suspious
that why this guy use pack(1) on this kind of struct, but we can just
ignore it and focus on the underlying reason why the usage cause the
failure.

Thanks in advance.

-
narke
 
P

peter koch

In our project, one used the following struct

#pragma pack(1)
struct Foo {
  uint8_t   b1;
  uint8_t   b2;
  uint8_t   b3;
  std::vector<uint8_t>  buf;
  ...};

#pragma pack()

this work on PC, but not on ARM target using a gcc/g++ cross
compiler.  The problem is, on ARM, after defined a variable of  Foo
and want to access a method of buf, such as

    Foo foo;
    foo.buf.resize(100);

the program will exit.  I guss it's a segment failure.

Can you experts explain for me the reason?  I know, it is  suspious
that why this guy use pack(1) on this kind of struct, but we can just
ignore it and focus on the underlying reason why the usage cause the
failure.

Because some processors require that certain types are properly
aligned. So stop packing your structures: even on x86 architectures,
packed structures (although allowed) cause the code to run much more
slowly.

/Peter
 
R

Rolf Magnus

Steven said:
In our project, one used the following struct

#pragma pack(1)
struct Foo {
uint8_t b1;
uint8_t b2;
uint8_t b3;
std::vector<uint8_t> buf;
...
};
#pragma pack()

this work on PC, but not on ARM target using a gcc/g++ cross
compiler. The problem is, on ARM, after defined a variable of Foo
and want to access a method of buf, such as

Foo foo;
foo.buf.resize(100);

the program will exit. I guss it's a segment failure.


Can you experts explain for me the reason?

Because you enforce mis-alingment. And while PCs can still access
mis-algined data (though at reduced speed), an ARM CPU simply can't.
I know, it is suspious that why this guy use pack(1) on this kind of
struct, but we can just ignore it and focus on the underlying reason why
the usage cause the failure.

Well that reason is at the same time the reason why this looks suspicious,
since it's also the reason why you shouldn't do that in the first place.
 
S

Steven Woody

Because you enforce mis-alingment. And while PCs can still access
mis-algined data (though at reduced speed), an ARM CPU simply can't.


Well that reason is at the same time the reason why this looks suspicious,
since it's also the reason why you shouldn't do that in the first place.


Could you explain? Thanks.

And, I am thinking another question: whether using packing a struct is
itself a bad notion at all. You know, we are writting a network
program, other members in the team tends to define a structure for
every kind of packet come in/out from/to the network, because there is
no padding in packets in the form of byte-stream, so "#pragma pack(1)"
or "__attribute__((packed))" was used almost everywhere. I personally
dont' prefer this method, I just do the packet parsing and framing in
a character by character way, hence don't mapping packets to any in-
memory structure. Do these two kind of programming style imply
anything? What kind do you prefer?

Thanks in advance.
 
I

Ian Collins

Steven said:
Could you explain? Thanks.
The quote the paragraph before:
And, I am thinking another question: whether using packing a struct is
itself a bad notion at all.

It is if you want portable code. Some common processors simply don't
support it.
You know, we are writting a network
program, other members in the team tends to define a structure for
every kind of packet come in/out from/to the network, because there is
no padding in packets in the form of byte-stream, so "#pragma pack(1)"
or "__attribute__((packed))" was used almost everywhere.

So they don't care about portability? Not only is packing an issue,
there's byte order as well.
I personally
dont' prefer this method, I just do the packet parsing and framing in
a character by character way, hence don't mapping packets to any in-
memory structure. Do these two kind of programming style imply
anything? What kind do you prefer?
The latter.
 
I

Ian Collins

Ian said:
So they don't care about portability? Not only is packing an issue,
there's byte order as well.

The latter.
I should clarify, I do use structures for packet types, but I don't just
pull them off the wire. I use a binary stream class to serialise the
structures and manage reading from and writing to the network.
 
S

Steven Woody

I should clarify, I do use structures for packet types, but I don't just
pull them off the wire. I use a binary stream class to serialise the
structures and manage reading from and writing to the network.

This is indeed what I did though I dont use an explicit stream class
as yours, but I transfer merely byte stream (std::vector<uint8_t> for
example) between upper and lower software layers, and I write utility
function to encode any internal structure to a std::vector<uint8_t>.
For reading packet from byte stream, serialization is not even enough,
since valid packets may come between noise, that means I have to parse
and recognize them from the stream, hence, an Finite-State-Machine is
always employed, do this way means I read in characters one by one and
pop up a valid packet to upper layer if any found.

In your previous post, I thing I don't fully understand the term 'mis-
alignment': "Because you enforce mis-alingment. And while PCs can
still access
PS. Answer a question you asked: there is not byte-ordering problem
in the project, you know, PC and ARM both use little-endian which is
same as byte order used in our communication protocol.
 
I

Ian Collins

Steven said:
*Please* don't quote sigs


In your previous post, I thing I don't fully understand the term 'mis-
alignment':

Most, if not all processors prefer types to be aligned to their natural
boundary, say 4 bytes for an int. When an int value is not aligned on a
4 byte boundary, the processor may require one or two extra bus cycles
to read the value form memory.

Some processors (Sparc for example) *require* types to be aligned to
their natural boundary. They will generate a hardware trap it you
attempt a misaligned access.
 
J

James Kanze

Could you explain? Thanks.

Because that's what pack does, as Rolf explained. Practically
speaking, just about any use of pack is suspicious. About the
only case I can think of where you might use it would be in
driver software, in the kernel, and even there, I've never found
it useful.
And, I am thinking another question: whether using packing a
struct is itself a bad notion at all.
Very.

You know, we are writting a network program, other members in
the team tends to define a structure for every kind of packet
come in/out from/to the network, because there is no padding
in packets in the form of byte-stream, so "#pragma pack(1)" or
"__attribute__((packed))" was used almost everywhere.

Which is just stupid. Packing is not the only aspect which has
to be considered. It makes a lot of sense to defined structures
(or even better, classes) for network packets, but you still
have to marshal and unmarshal, at the byte level, in order to
respect variations in the representation. (The most frequent
variation for integral types is byte order and size, although
there are machines which don't use 2's complement. For floating
point, of course, there's even more variation.)
I personally dont' prefer this method, I just do the packet
parsing and framing in a character by character way, hence
don't mapping packets to any in- memory structure.

Which is the only way which really works.
Do these two kind of programming style imply
anything? What kind do you prefer?

Yes. The use of a byte dump and pack means that the authors
were incompetent.
 
S

Steven Woody

Because that's what pack does, as Rolf explained. Practically
speaking, just about any use of pack is suspicious. About the
only case I can think of where you might use it would be in
driver software, in the kernel, and even there, I've never found
it useful.


Which is just stupid. Packing is not the only aspect which has
to be considered. It makes a lot of sense to defined structures
(or even better, classes) for network packets, but you still
have to marshal and unmarshal, at the byte level, in order to
respect variations in the representation. (The most frequent
variation for integral types is byte order and size, although
there are machines which don't use 2's complement. For floating
point, of course, there's even more variation.)


Which is the only way which really works.


Yes. The use of a byte dump and pack means that the authors
were incompetent.

--
James Kanze (GABI Software) email:[email protected]
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34

Thank you, Rolf, Ian and James. Your kindly shared opinions made me
understand the topic more clear than ever.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,567
Members
45,041
Latest member
RomeoFarnh

Latest Threads

Top