Hi, Following code:
1: int main() 2: { 3: char Buff[3]; 4: *((short*)(Buff+1)) = 0xFFFF; 5: }
4: *((short*)(Buff+1)) = 0xFFFF; 0x0008011C 4904 LDR R1,[PC,#0x0010] 0x0008011E 2001 MOV R0,#0x01 0x00080120 4468 ADD R0,SP 0x00080122 8001 STRH R1,[R0,#0x00]
Your method of storing a multi-byte data object directly in a byte-oriented buffer is broken as you know and non-portable as Andy has indicated. "htons" and "htonl" deal with the endian issues of portability, but both still yield a multi-byte data object that will cause a fault on some architectures when stored unaligned. The conventional means of storing into communications buffers is not as attractive as doing it directly like you've done. You have to store the individual bytes one at a time. Take a look at any source code for protocol stacks and you will see it done that way.
unsigned char *store_htons(unsigned char *p, unsigned short value) { value = htons(value); p[1] = value & 0xFF; value >>= 8; p[0] = value & 0xFF; return (p + 2); } unsigned char *store_htonl(unsigned char *p, unsigned long value) { value = htonl(value); p[3] = value & 0xFF; value >>= 8; p[2] = value & 0xFF; value >>= 8; p[1] = value & 0xFF; value >>= 8; p[0] = value & 0xFF; return (p + 4); } void foo(void) { extern void send_msg(unsigned char *msg); unsigned char buf[16]; unsigned char *p = buf; p = store_htons(0xFFFF, p); *p++ = 1; *p++ = 2; p = store_htonl(0x12345678, p); /* ... */ send_msg(buf); }
For processors that require alignment, it is, as far as I know, always problematic to store entities larger than the slot by typecasting regardless of processor and compiler. This has been true for every processor/compiler set I have worked with when the processor required aligning. Erik
ANSI does not specify the usage of un-aligned pointers (because the underlaying hardware might not support it). The x86 architecture has hardware support for un-aligned accesses. The ARM architecture requries software support. Therefore we have implemented the __packed attribute. See: http://www.keil.com/support/man/docs/ca/ca_le_packed.htm The following code will allow what you want:
void main(void) { char Buff[3]; *((short __packed *)(Buff+1)) = 0xFFFF; }
"With other compilers on other platforms (Borland and I386 for example) such a problem doesn't appear." What is the extent of the testing on which you base this statement? "The x86 architecture has hardware support for un-aligned accesses." So, even though it "works", the hardware has to jump through hoops and the performance will be degraded. So this technique loses you both performance and portability. Thus, the "conventional" method described by Dan may not be as "unattractive" as it appears at first sight...!
Andy, Dan, Erik, Reinhard. Thanks for advices. I am currently offline and can't discuss in time. Of course performance and portability are important criteria. But may be other reasons for using bytealigning. It is privilege of programmer to decide wich of criteria is more significant. For my problem performance and portability are less importance. I think that for compiler it is advantageous to give different abilities for programmers. And, as Reinhard instructed, the CARM has ability of bytealigning. It is what I want. Thanks.