简体   繁体   中英

Pointer cast into char* array

I'm fairly new to C++ and I'm having difficulty wrapping my head around what is going on in the final line of the below:

int numToSend = bs->GetSize();
char *  tBuf = new char[NUM_LENGTH_BYTES + numToSend];
*(WORD*)tBuf = htons((WORD)numToSend);

So htons is returning a u_short or WORD, but the cast on tBuf is somewhat confusing to me. Is it something along the lines of "the value pointed to by tBuf is cast as a WORD pointer and assigned the return from htons"?

I believe this is a fairly unsafe operation in most cases, what would be the best practice here?

It may not be a recommended practice, but AFAIK, it is safe. It is true that in general, taking a pointer to P, casting it to a pointer to Q and using it as a pointer to Q leads to undefined behaviour. Here it looks even worse, because the alignment requirement of char are known to be the weakest possible.

But the char * tBuf pointer has been obtained through a new expression. Such a new expression internally rely on a allocation function to obtain storage, and draft n4296 for c++14 says in 3.7.4.1 Allocation functions [basic.stc.dynamic.allocation] §2:

The allocation function attempts to allocate the requested amount of storage. If it is successful, it shall return the address of the start of a block of storage whose length in bytes shall be at least as large as the requested size... The pointer returned shall be suitably aligned so that it can be converted to a pointer of any complete object type with a fundamental alignment requirement (3.11) and then used to access the object or array in the storage allocated (until the storage is explicitly deallocated by a call to a corresponding deallocation function).

So this line *(WORD*)tBuf = htons((WORD)numToSend); only does perfectly defined operations:

  • convert numToSend from an integer type to an unsigned type, and 4.7 Integral conversions [conv.integral] says:

    1. A prvalue of an integer type can be converted to a prvalue of another integer type...

    2. If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type)

  • call htons with a WORD or uint16_t as parameter to return a uint16_t or WORD

  • converts a pointer obtained by new to a WORD * and uses that pointer to access the object in the storage allocated

Simply, the value of the first two bytes of the allocated array is now unspecified. More exactly it is the byte representation of the WORD in the particular implementation.

But it is still allowed to access the allocated array as a character array, even if the first bytes now contain a WORD, because it is explicitely allowed per the so called strict aliasing rule 3.10 Lvalues and rvalues [basic.lval] §10 :

If a program attempts to access the stored value of an object through a glvalue of other than one of the following types the behavior is undefined:
...
(10.8) — a char or unsigned char type.


If the tBuf pointer had not been obtained through a new expression, the only correct way would have been to do a memcpy :

WORD n_numToSend = htons(numToSend);
memcpy(tBuf, &n_numToSend, sizeof(WORD));

As this one is allowed for any pointer provided the storage is big enough, it is what I would call the recommended practice.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM