Treating 'char' Structure Members as Contiguous Bytes

M

Martin

The following compiles cleanly on gcc3.0.4 using -W -Wall -ansi -
pedantic. Lint gives this warning:
_
p_member_09 = p_start + OFFSET_TO_MEMBER_09;
t_offset.c 27 Warning 416: creation of out-of-bounds pointer (33
beyond end of data) by operator ptr+int' [Reference: file t_offset.c:
lines 26, 27]

The underscore Lint uses to indicate the point of warning is over the
'O' in OFFSET_TO_MEMBER_09.

My question is this. Is the technique used here well-defined and safe
practice?


typedef unsigned char uchar;

struct byte_array {
uchar member_01;
uchar member_02[8];
uchar member_03[2];
uchar member_04[2];
uchar member_05[8];
uchar member_06[2];
uchar member_07[2];
uchar member_08[8];
uchar member_09[2];
uchar member_10[2];
};

struct byte_array byte_array;

#define OFFSET_TO_MEMBER_06 21
#define OFFSET_TO_MEMBER_09 33

int main( void )
{
uchar *p_start;
uchar *p_member_09;

p_start = &byte_array.member_01;
p_member_09 = p_start + OFFSET_TO_MEMBER_09;

return 0;
}
 
R

Richard Bos

Martin said:
The following compiles cleanly on gcc3.0.4 using -W -Wall -ansi -
pedantic. Lint gives this warning:
_
p_member_09 = p_start + OFFSET_TO_MEMBER_09;
t_offset.c 27 Warning 416: creation of out-of-bounds pointer (33
beyond end of data) by operator ptr+int' [Reference: file t_offset.c:
lines 26, 27]
My question is this. Is the technique used here well-defined and safe
practice?

I'll let others figure out the exact safety of the technique you use -
my first instincts say that it's undefined behaviour in theory, but very
unlikely to break - and suggest that regardless of the outcome, you
switch to a guaranteed safe technique: use offsetof(). You'll need to
#include <stddef.h>.

Richard
 
T

Thad Smith

Martin said:
The following compiles cleanly on gcc3.0.4 using -W -Wall -ansi -
pedantic. Lint gives this warning:
_
p_member_09 = p_start + OFFSET_TO_MEMBER_09;
t_offset.c 27 Warning 416: creation of out-of-bounds pointer (33
beyond end of data) by operator ptr+int' [Reference: file t_offset.c:
lines 26, 27]

The underscore Lint uses to indicate the point of warning is over the
'O' in OFFSET_TO_MEMBER_09.

My question is this. Is the technique used here well-defined and safe
practice?


typedef unsigned char uchar;

struct byte_array {
uchar member_01;
uchar member_02[8];
uchar member_03[2];
uchar member_04[2];
uchar member_05[8];
uchar member_06[2];
uchar member_07[2];
uchar member_08[8];
uchar member_09[2];
uchar member_10[2];
};

struct byte_array byte_array;

#define OFFSET_TO_MEMBER_06 21
#define OFFSET_TO_MEMBER_09 33

int main( void )
{
uchar *p_start;
uchar *p_member_09;

p_start = &byte_array.member_01;
p_member_09 = p_start + OFFSET_TO_MEMBER_09;

return 0;
}

It is not defined because the struct may have padding between members
(although it is unlikely when the members are arrays of unsigned char).

You can instead write
p_member_09 = byte_array.member_09;
or
p_member_09 = (uchar*)byte_array + offsetof (struct byte_array, member_09);
 
A

Andrey Tarasevich

Martin said:
...
My question is this. Is the technique used here well-defined and safe
practice?
...

From the pedantic point of view of the standard C language, this
technique is not safe. It caused undefined behavior. Just a mere attempt
to add more than 1 to '&byte_array.member_01' is already UB.

Now, somewhere in the low level platform-specific code this techniques
might be considered acceptable, but, once again, you have to know what
your are doing and be ready for the unexpected. It might make sense to
add a bunch of STATIC_ASSERTs that might look as follows

STATIC_ASSERT(OFFSET_TO_MEMBER_06 == offsetof(byte_array, member_09))

and so on (look up STATIC_ASSERT on Google for possible implementations).
 
A

Army1987

Martin wrote:
[...]
typedef unsigned char uchar;

struct byte_array {
uchar member_01;
uchar member_02[8]; [...]
uchar member_10[2];
};

struct byte_array byte_array;

#define OFFSET_TO_MEMBER_06 21
#define OFFSET_TO_MEMBER_09 33
#include said:
int main( void )
{
uchar *p_start;
uchar *p_member_09;

p_start = &byte_array.member_01;
p_member_09 = p_start + OFFSET_TO_MEMBER_09;
Why not p_start + offsetof(byte_array, member_09)?
[...]
 
M

Martin

My thanks to you all for your responses.

Although it's a perfectly reasonable assumption that the code I posted
was mine, it is in fact code I am maintaining and I would not have
written it that way. I posted to confirm what I already suspected -
that it evoked undefined behaviour. Andrey Tarasevich put it
succinctly, and Richard Bos has confirmed what is happening in
practice - the code works. That is unfortunate because there is no
motivation to fix it by those that can authorise such a thing. I can
make a unilateral decision to do so, but they then would have to be
willing to merge my changes into their code.
 

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

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top