Hello all,
Previously i was using MDKARM 4.0 and now i've upgraded to the 4.7. I am writing the program for LPC17xx. In the previous version i was using unsigned long long data type for 64 bit data storage. When i want to store the data in buffer i was using following
*(unsigned long long *)buf->dptr = n->ex;
where ex is __packed unsigned long long data type.
I used __packed because of the data alignment boundary.
Now when i am upgraded to 4.7 same instruction gave me unaligned fault, may be because of some changes in compiler. Just out of the hunch i changes above statement to following
*(__packed unsigned long long *)buf->dptr = n->ex;
Now there is now unaligned fault. I just wanted to ask if it is the correct way or it may lead to unexplained behavior in future. If not what could be the correct way to typecast. Please point me in correct direction.
Thanks in advance Ra
No, packing your data does not circumvent any unaligned access. It just hides the unaligned access by having the compiler thow in lots of extra instructions.
Packet data is something that is used when needing to handle many records, where there is a significant size advantage of packing the data.
For just a few packed entries, the cost of packing (lots of extra code generated) normally makes it too costly - if the RAM is so tight, then the wrong processor is normally used. And remember that in some situations, the struct was already optimal while the extra keyword still did force the compiler to assume it wasn't.
When doing transfers, there is also a good idea to pack data to reduce the amount of information sent - but in that case, it is normally important to lock down align + big/little endian + word size + ... so then it's normally best to explicitly pack/unpack the data. I.e. not use any compiler-specific keyword but to add explicit C code that does the packing/unpacking. That makes sure that the same data can be packed/unpacked even if the two sides are using different architectures.
When having a generic buffer that is intended to store different types of information, it is normally a good idea to define that buffer in a way that it automagically gets a good enough align.
If you ask for an array of 8 uint8_t, then the compiler can use an odd align. If you ask for an array of 4 uint16_t, then you get the same buffer size, but you know the buffer will have even align if the architecture requires it. If you ask for an array of 2 uint32_t, then you get the same buffer size, but you will get an align n*4 if the architecture requires it. If you ask for an array of 1 uint64_t, then you get the same buffer size, but you will get an align n*8 if the architecture requires it.
So:
struct { type_t type_info; ///< What type of info stored in my generic buffer. ... uint64_t buf[1]; ///< Generic buffer for storing different type of info. };
The above would have the compiler add a suitable number of pad bytes to the structure, if that is required for buf[] to get an align good enough for use with 64-bit integers. Or 32-bit integers. Or 16-bit integers.
In what way(s), exactly, do you think that memory access needs "improving"?
One reason why compilers typically add packing is precisely to "improve" memory accesses - by avoiding the need to do unaligned accesses.
So why not just leave the compiler to get on with it?
Are you trying to force some communications protocol frame structure onto data in memory? If so, it may well be better to avoid all these problems by simply not doing that - and just "serialising" that data onto the communication medium, and "de-serialising" it from the communication medium...
Try searching the forum for other discussions on those terms...
I've checked memcpy, but it is not working with __packed data types. The error is
error: #167: argument of type "__packed unsigned long long *" is incompatible with parameter of type "const void *restrict"
I think i will be better off to use array of smaller data types for unsigned long long data type and i'm also looking at the structure arrangement to improve memory access.
It is almost certainly quite irrelevant what "ex" is. The problem is on the left hand side of that line.
may be because of some changes in compiler.
Only indirectly. The error is because that line of code has been wrong all along --- that __packed keyword was strictly necessary. If it appeared to work as desired before, that was most likely by pure coincidence.
You cannot cast up an arbitrary pointer to a pointer type with alignment requirements as high as those of a 64-bit type on a 32-bit ARM, and expect it to just work. Not unless you're absolutely sure that the value of dptr is sufficiently aligned, that is.
You would have been better off spelling that as
memcpy(buf->dtr, n->ex, sizeof(unsigned long long));
(One) of my assumptions is that if this declaration:
does not generate a warning or an error is that it must be allowable.
That said, my main point is that if the value being stored from a declared packed location into a non-declared location, regardless of how a pointer is cast, should generate a warning/error as the source and destination addresses do not have the same restriction.
For example, if the source is say at address 0x80000001 and the destination is at 0x80000010 then it should be flagged as potentally an incorrect transfer strictly based on address incompatibility, which is what I assume a compiler should check. It may be checking other things too, but I have no knowledge as to what they would be.
You are assuming that __packed can be used like a typecast - is that true?
View all questions in Keil forum