Accessing members of array as a different type

J

James A

Hi,

I'm having trouble geting my head around this, although I know it's a pretty
basic question.

I have an application whereby an area of RAM is mapped to an array:

unsigned char NV[128];

Two consequtive elements are used to hold an unsigned int (2 bytes on this
platform). How do I access it as an unsigned int?

e.g.
unsigned int test;
....
test = *(unsigned int *)(&(NV[15]);

In this case, I'm trying to retrieve the unsigned int value represented by
elements 15 & 16 of the array. It does not seem to be working.

Could someone please explain what I'm doing wrong.

Many thanks,

James
 
J

Jens.Toerring

James A said:
I'm having trouble geting my head around this, although I know it's a pretty
basic question.
I have an application whereby an area of RAM is mapped to an array:
unsigned char NV[128];
Two consequtive elements are used to hold an unsigned int (2 bytes on this
platform). How do I access it as an unsigned int?
e.g.
unsigned int test;
...
test = *(unsigned int *)(&(NV[15]);
In this case, I'm trying to retrieve the unsigned int value represented by
elements 15 & 16 of the array. It does not seem to be working.

It would be helpful to tell what you mean by "not seem to be working".
That construct could, for example, crash your program with a SIGBUS
error because of an unaligned access. Or it could work but deliver
an unexpected result. But what you expect is something that no-one
can figure out from what you write, so it could be that the numbers
you're expecting in memory are stored in big-endian order while you
try to do all of that on a little endian machine etc. Or it could
be because what you try to read belongs actually to two different
2-byte numbers (if, as you write, all the 128 bytes are occupied
by 64 2-byte numbers).
Regards, Jens
 
F

Flash Gordon

I'm having trouble geting my head around this, although I know it's a
pretty basic question.

I have an application whereby an area of RAM is mapped to an array:

unsigned char NV[128];

Two consequtive elements are used to hold an unsigned int (2 bytes on
this platform). How do I access it as an unsigned int?

e.g.
unsigned int test;
...
test = *(unsigned int *)(&(NV[15]);

You seem to have mismatched brackets. I assume this was a typo and not
the problem in your actual code.
In this case, I'm trying to retrieve the unsigned int value
represented by elements 15 & 16 of the array. It does not seem to be
working.

Could someone please explain what I'm doing wrong.

What you are doing wrong is invoking undefined behaviour when you don't
need to. One reason why this might fail on real implementations is due
to alignment restrictions, other reasons for failure include having more
than 5 minutes in a day. Depending on what you are trying to achieve
something like
test = ((unsigned int)NV[15] << CHAR_BIT) || NV[16]
or possibly
test = ((unsigned int)NV[16] << CHAR_BIT) || NV[15]

Of course, if by "area of RAM is mapped to an array" you mean some RAM
written to by some other (e.g. if it is DPRAM) then you would also need
to declare NV as volatile.
 
M

Mike Wahler

James A said:
Hi,

I'm having trouble geting my head around this, although I know it's a pretty
basic question.

I have an application whereby an area of RAM is mapped to an array:

unsigned char NV[128];

Two consequtive elements are used to hold an unsigned int (2 bytes on this
platform). How do I access it as an unsigned int?

e.g.
unsigned int test;
...
test = *(unsigned int *)(&(NV[15]);

In this case, I'm trying to retrieve the unsigned int value represented by
elements 15 & 16 of the array. It does not seem to be working.

Could someone please explain what I'm doing wrong.

You don't give enough information. E.g.
How was the data originally stored?

#include <stdio.h>

int main()
{
unsigned char NV[128] = {0};
unsigned int test = 0;

NV[15] = NV[16] = 0xAA;
test = *(unsigned int *)(NV + 15);

printf("%u\n", test); /* prints 43690 for implementations with
*/
/* two-byte unsigned int and for 'little-endian'
*/
/* (e.g. most PC's) platforms with a larger
*/
/* unsigned int
*/

return 0;
}

-Mike
 
J

James A

Mike Wahler said:
James A said:
Hi,

I'm having trouble geting my head around this, although I know it's a pretty
basic question.

I have an application whereby an area of RAM is mapped to an array:

unsigned char NV[128];

Two consequtive elements are used to hold an unsigned int (2 bytes on this
platform). How do I access it as an unsigned int?

e.g.
unsigned int test;
...
test = *(unsigned int *)(&(NV[15]);

In this case, I'm trying to retrieve the unsigned int value represented by
elements 15 & 16 of the array. It does not seem to be working.

Could someone please explain what I'm doing wrong.

You don't give enough information. E.g.
How was the data originally stored?

#include <stdio.h>

int main()
{
unsigned char NV[128] = {0};
unsigned int test = 0;

NV[15] = NV[16] = 0xAA;
test = *(unsigned int *)(NV + 15);

printf("%u\n", test); /* prints 43690 for implementations with
*/
/* two-byte unsigned int and for 'little-endian'
*/
/* (e.g. most PC's) platforms with a larger
*/
/* unsigned int
*/

return 0;
}

-Mike

Many thanks Mike, Flash and Jens for your replies and advice.

Sorry for the lack of info. Here is hopefully what is needed:

By not working, I mean the unsigned int value stored is not the same value
returned later on.

Here is the code that should be storing the value:

unsigned int a, b;
...
*(unsigned int *)(&(NV[15])) = a;

The code that retreives the value later on in the code is this:

b = *(unsigned int *)(&(NV[15]));

[Apologies for the bracket error in the original post]

But in my testing, b does not equal a.

Debugging is somewhat tricky (the platform is a small embedded processor
[PIC12]) but the symptoms suggest that the most significant byte of the
unsigned int is being retrieved with the incorrect contents. The compiler
documentation says it uses little-endian format for its 16-bit unsigned
ints.

This problem might be down to me overwriting the area of the array concerned
elsewhere in the code. Could someone please say if the code above should
work ok. Then I can either eliminate it from my search, or go about fixing
it.

Thanks for all your help and patience!

James
 
J

Jens.Toerring

James A said:
By not working, I mean the unsigned int value stored is not the same value
returned later on.
Here is the code that should be storing the value:
unsigned int a, b;
...
*(unsigned int *)(&(NV[15])) = a;
The code that retreives the value later on in the code is this:
b = *(unsigned int *)(&(NV[15]));

That looks pretty good and should work (unless there are some align-
ment issues on your machine, but if this does not crashes the program
it should not be a problem). Actually, you could simplify that to

b = * ( unsigned int * ) ( NV + 15 );

etc., which I at least would find easier to read.
But in my testing, b does not equal a.
Debugging is somewhat tricky (the platform is a small embedded processor
[PIC12]) but the symptoms suggest that the most significant byte of the
unsigned int is being retrieved with the incorrect contents.

Are you sure you're not writing to some hardware registers instead
of some simple memory? I just ask because you were writing about a
"memory range" and now about an "embedded processor" (which may use
memory mapped I/O) - so when there's some hardware register mapped
into that memory range and you accidentally hit one all bets are off,
of course...
The compiler documentation says it uses little-endian format for
its 16-bit unsigned ints.

If you compare what you have written yourself with what you read endian-
ness shouldn't be an issue here - it could be a problem if that would be
a buffer with some binary data you have received from a different machine.
This problem might be down to me overwriting the area of the array concerned
elsewhere in the code. Could someone please say if the code above should
work ok. Then I can either eliminate it from my search, or go about fixing
it.

I don't see why it shouldn't work. Checking if it does should be not too
difficult - write a short program that writes to a memory location this
way and read in what you have written immediately again. If this fails
something strange is going on (while I don't guess it will, one never
knows until one has tested it;-), otherwise it's a safe bet that some-
thing has overwritten the memory in between writing and reading.

If it does not work, you still can go the clean, portable road by
simply using memcpy(), i.e.

memcpy( NV + 15, &a, sizeof a );
...
memcpy( &b, NV + 15, sizeof b );

If this also fails you can be sure that either your memory is bad or
that it's not real memory at all.
Regards, Jens
 
J

James A

James A said:
By not working, I mean the unsigned int value stored is not the same value
returned later on.
Here is the code that should be storing the value:
unsigned int a, b;
...
*(unsigned int *)(&(NV[15])) = a;
The code that retreives the value later on in the code is this:
b = *(unsigned int *)(&(NV[15]));

That looks pretty good and should work (unless there are some align-
ment issues on your machine, but if this does not crashes the program
it should not be a problem). Actually, you could simplify that to

b = * ( unsigned int * ) ( NV + 15 );

etc., which I at least would find easier to read.
But in my testing, b does not equal a.
Debugging is somewhat tricky (the platform is a small embedded processor
[PIC12]) but the symptoms suggest that the most significant byte of the
unsigned int is being retrieved with the incorrect contents.

Are you sure you're not writing to some hardware registers instead
of some simple memory? I just ask because you were writing about a
"memory range" and now about an "embedded processor" (which may use
memory mapped I/O) - so when there's some hardware register mapped
into that memory range and you accidentally hit one all bets are off,
of course...
The compiler documentation says it uses little-endian format for
its 16-bit unsigned ints.

If you compare what you have written yourself with what you read endian-
ness shouldn't be an issue here - it could be a problem if that would be
a buffer with some binary data you have received from a different machine.
This problem might be down to me overwriting the area of the array concerned
elsewhere in the code. Could someone please say if the code above should
work ok. Then I can either eliminate it from my search, or go about fixing
it.

I don't see why it shouldn't work. Checking if it does should be not too
difficult - write a short program that writes to a memory location this
way and read in what you have written immediately again. If this fails
something strange is going on (while I don't guess it will, one never
knows until one has tested it;-), otherwise it's a safe bet that some-
thing has overwritten the memory in between writing and reading.

If it does not work, you still can go the clean, portable road by
simply using memcpy(), i.e.

memcpy( NV + 15, &a, sizeof a );
...
memcpy( &b, NV + 15, sizeof b );

If this also fails you can be sure that either your memory is bad or
that it's not real memory at all.
Regards, Jens

Hi Jens,

Many thanks for your reply. I like your simplification of the code and will
switch to that - much more readable I agree! And thank you for confirming
that the code itself is not at fault - the problem must be somewhere else.

I didn't want to talk too much about the platform as I know this is a
generic C language group, so kept the details to a minimum. FWIW, the array
is declared using a qualifier that means it uses non-volatile memory in the
PIC - I use it to store various values that need to be retained across power
cycles. Unfortunately ROM space is incredibly tight so I had to switch from
discrete variables to a single, multi-purpose array in order to save a few
bytes in the compile size, and somewhere down the line this bug has crept
in.

Armed with your info and suggestions I should be able to track the problem
down soon.

Cheers,
James
 
F

Flash Gordon

By not working, I mean the unsigned int value stored is not the same
value returned later on.
Here is the code that should be storing the value:
unsigned int a, b;
...
*(unsigned int *)(&(NV[15])) = a;
The code that retreives the value later on in the code is this:
b = *(unsigned int *)(&(NV[15]));

That looks pretty good and should work (unless there are some align-
ment issues on your machine, but if this does not crashes the program
it should not be a problem). Actually, you could simplify that to [/QUOTE]

<snip>

Not true. The processor could just silently ignore the low bit of the
address or do something else even more screwy. Crashing is only the
nicest way it can fail.

If it does not work, you still can go the clean, portable road by
simply using memcpy(), i.e.

memcpy( NV + 15, &a, sizeof a );
...
memcpy( &b, NV + 15, sizeof b );

If this also fails you can be sure that either your memory is bad or
that it's not real memory at all.

This is a very good suggestion.
 

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,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top