我对C ++很陌生,而且我很难理解下面最后一行的内容:
int numToSend = bs->GetSize();
char * tBuf = new char[NUM_LENGTH_BYTES + numToSend];
*(WORD*)tBuf = htons((WORD)numToSend);
所以htons返回一个u_short或WORD,但tBuf上的强制转换对我来说有点混乱。它是否符合“tBuf指向的值被转换为WORD指针并从htons分配返回”的内容?
我相信在大多数情况下这是一个相当不安全的操作,这里最好的做法是什么?
答案 0 :(得分:2)
这可能不是推荐的做法,但AFAIK,它是安全的。确实,通常,将指针指向P,将其转换为指向Q的指针并将其用作指向Q的指针会导致未定义的行为。这看起来更糟糕,因为已知char
的对齐要求是最弱的。
但char * tBuf
指针已通过新表达式获得。这样一个新表达式内部依赖于分配函数来获取存储,而c.44的草案n4296在3.7.4.1分配函数中说明[basic.stc.dynamic.allocation]§2:
分配功能尝试分配所请求的存储量。如果成功,它应该 返回存储块的起始地址,其长度以字节为单位应至少与 请求的大小...返回的指针应适当对齐,以便可以转换 到具有基本对齐要求(3.11)的任何完整对象类型的指针然后使用 访问分配的存储中的对象或数组(直到通过调用显式释放存储 到相应的释放函数)。
因此,此行*(WORD*)tBuf = htons((WORD)numToSend);
仅执行完美定义的操作:
将numToSend
从整数类型转换为无符号类型,4.7整数转换[conv.integral]说:
整数类型的prvalue可以转换为另一个整数类型的prvalue ...
- 醇>
如果目标类型是无符号的,则结果值是与源一致的最小无符号整数 整数(模2n,其中n是用于表示无符号类型的位数)
使用WORD或uint16_t作为参数调用htons
以返回uint16_t或WORD
WORD *
并使用该指针访问已分配存储中的对象简单地说,现在未指定分配数组的前两个字节的值。更确切地说,它是特定实现中WORD的字节表示。
但是仍然允许将分配的数组作为字符数组访问,即使第一个字节现在包含WORD,因为根据所谓的严格别名规则 3.10 Lvalues,它是明确允许的。 rvalues [basic.lval]§10:
如果程序试图通过除了其中一个之外的glvalue访问对象的存储值 以下类型的行为未定义:
...
(10.8) - char或unsigned char类型。
如果未通过新表达式获取tBuf
指针,唯一正确的方法是memcpy
:
WORD n_numToSend = htons(numToSend);
memcpy(tBuf, &n_numToSend, sizeof(WORD));
由于存储器足够大,所以允许使用任何指针,这就是我所说的推荐做法。