在我的项目中,我们有一段这样的代码:
// raw data consists of 4 ints
unsigned char data[16];
int i1, i2, i3, i4;
i1 = *((int*)data);
i2 = *((int*)(data + 4));
i3 = *((int*)(data + 8));
i4 = *((int*)(data + 12));
Run Code Online (Sandbox Code Playgroud)
我和我的技术负责人谈到这个代码可能不便携,因为它试图将a unsigned char*转换为int*通常具有更严格的对齐要求的代码.但是技术主管说没关系,大多数编译器在转换后仍保持相同的指针值,我可以像这样编写代码.
坦率地说,我并不是真的相信.经过研究,我发现有些人反对使用上面的指针铸件,例如,这里和这里.
所以这是我的问题:
reinterpret_cast?之间有什么区别吗?我是C++ std :: stream的新手,我正在做一些测试.我有这个简单的代码:
int i = 10;
char c = 'c';
float f = 30.40f;
std::ofstream out("test.txt", std::ios::binary | std::ios::out);
if(out.is_open())
{
out<<i<<c<<f;
out.close();
}
Run Code Online (Sandbox Code Playgroud)
正如std::ios::binary我在test.txt文件中所期望的那样打开流以具有二进制表示形式i,c并且f,但是我有10c30.4.
你能告诉我我做错了什么吗?
大多数有经验的程序员都知道数据对齐对于程序的性能很重要.我看到一些程序员编写的程序分配比他们需要的更大的缓冲区大小,并使用对齐的指针作为开始.我想知道我应该在我的程序中这样做,我不知道是否有任何保证C++的新操作返回的地址对齐.所以我写了一个小程序来测试
for(size_t i = 0; i < 100; ++i) {
char *p = new char[123];
if(reinterpret_cast<size_t>(p) % 4) {
cout << "*";
system("pause");
}
cout << reinterpret_cast<void *>(p) << endl;
}
for(size_t i = 0; i < 100; ++i) {
short *p = new short[123];
if(reinterpret_cast<size_t>(p) % 4) {
cout << "*";
system("pause");
}
cout << reinterpret_cast<void *>(p) << endl;
}
for(size_t i = 0; i < 100; ++i) {
float *p = new float[123];
if(reinterpret_cast<size_t>(p) % 4) {
cout …Run Code Online (Sandbox Code Playgroud) 为了克服对齐问题,我需要记忆成一个临时的.临时的那种类型是什么?gcc抱怨以下reinterpret_cast将破坏严格的别名规则:
template <typename T>
T deserialize(char *ptr) {
static_assert(std::is_trivially_copyable<T>::value, "must be trivially copyable");
alignas(T) char raw[sizeof(T)];
memcpy(raw, ptr, sizeof(T));
return *reinterpret_cast<T *>(raw);
}
Run Code Online (Sandbox Code Playgroud)
(例如,当T为"长"时).
我不想定义T,因为我不想在覆盖之前构造T.
在一个联合中,不写一个成员然后读另一个计数作为未定义的行为?
template<typename T>
T deserialize(char *ptr) {
union {
char arr[sizeof(T)];
T obj;
} u;
memcpy(u.arr, ptr, sizeof(T)); // Write to u.arr
return u.obj; // Read from u.obj, even though arr is the active member.
}
Run Code Online (Sandbox Code Playgroud) 我使用std::array的chars到持有未知的原始类型,这是不超过10个字节长,像这样的一个值:
std::array<char, 10> val;
*reinterpret_cast<double*>(val.data()) = 6.3;
//blah blah blah...
double stuff = *reinterpret_cast<double*>(val.data());
Run Code Online (Sandbox Code Playgroud)
我已经读过,来回转换char *并不是未定义的,因为编译器假设char *可以为任何类型的值设置别名.当值放在(我假设的)char对象内部的s 数组时,这仍然有效吗?
注意:我知道我可以在这里使用union,但这会导致我正在做的大量样板代码,并且我想在必要时避免它,因此问题.
该计划 - 某种旧式网络消息传递:
// Common header for all network messages.
struct __attribute__((packed)) MsgHeader {
uint32_t msgType;
};
// One of network messages.
struct __attribute__((packed)) Msg1 {
MsgHeader header;
uint32_t field1;
};
// Network receive buffer.
uint8_t rxBuffer[MAX_MSG_SIZE];
// Receive handler. The received message is already in the rxBuffer.
void onRxMessage() {
// Detect message type
if ( ((const MsgHeader*)rxBuffer)->msgType == MESSAGE1 ) { // Breaks strict-aliasing!
// Process Msg1 message.
const Msg1* msg1 = (const Msg1*)rxBuffer;
if ( msg1->field1 == …Run Code Online (Sandbox Code Playgroud) 请考虑以下代码:
int i = 1;
char c[sizeof (i)];
memcpy(c, &i, sizeof (i));
cout << static_cast<int>(c[0]);
Run Code Online (Sandbox Code Playgroud)
请忽略这是否是好代码.我知道输出取决于系统的字节顺序.这只是一个学术问题.
这段代码是:
在阅读了下面的1和2 Q / As并在带有GCC和MSVC的x86架构上使用了下面讨论的技术多年之后,没有看到问题,现在我对应该是正确的东西感到非常困惑,但是这也是使用C ++进行序列化然后反序列化二进制数据的重要“最有效”方法。
给出以下“错误”代码:
int main()
{
std::ifstream strm("file.bin");
char buffer[sizeof(int)] = {0};
strm.read(buffer,sizeof(int));
int i = 0;
// Experts seem to think doing the following is bad and
// could crash entirely when run on ARM processors:
i = reinterpret_cast<int*>(buffer);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
现在,据我所知,重新解释类型转换向编译器表明它可以将缓冲区中的内存视为整数,并且随后可以发出整数兼容指令,这些指令要求/假定所讨论的数据具有某些对齐方式-唯一的开销是当CPU检测到其试图执行面向对齐指令的地址实际上未对齐时,多余的读取和移位。
那就是说,上面提供的答案似乎表明,就C ++而言,这都是未定义的行为。
假定将从中进行强制转换的缓冲区位置的对齐方式不一致,那么,对于此问题,唯一的解决方案是将字节一乘一地复制吗?也许有一种更有效的技术?
此外,多年来,我已经看到很多情况,其中将完全由Pod组成的结构(使用特定于编译器的编译指示来删除填充)转换为char *,然后写入文件或套接字,然后再读回缓冲区并且将缓冲区转换回原始结构的指针(忽略机器之间的潜在字节序和浮点/双格式问题),这种代码是否也被视为未定义的行为?
以下是更复杂的示例:
int main()
{
std::ifstream strm("file.bin");
char buffer[1000] = {0};
const std::size_t size = sizeof(int) + sizeof(short) + sizeof(float) + sizeof(double);
const std::size_t weird_offset = …Run Code Online (Sandbox Code Playgroud) 我试图理解c ++中的const.我在下面的代码片段中写了这个:
const int x=5;
int *ptr;
ptr=(int*)&x;
cout<<"address of x="<<&x<<endl;
cout<<"value of ptr="<<ptr<<endl;
*ptr=11;
cout<<"*ptr="<<*ptr<<endl;
cout<<"x="<<x;
Run Code Online (Sandbox Code Playgroud)
输出是
address of x=0x28fef8
address of ptr=0x28fef8
*ptr=11
x=5
Run Code Online (Sandbox Code Playgroud)
由于ptr指向x,我确信*ptr和x的值是相同的.为什么价值不同?我知道x是const,但是,我通过执行*ptr来改变内存地址的值.请告诉我我错过了什么.
如何避免严格别名规则违规,试图修改char*sha256函数的结果.
计算哈希值:
std::string sha = sha256("some text");
const char* sha_result = sha.c_str();
unsigned long* mod_args = reinterpret_cast<unsigned long*>(sha_result);
Run Code Online (Sandbox Code Playgroud)
得到2个64位:
unsigned long a = mod_args[1] ^ mod_args[3] ^ mod_args[5] ^ mod_args[7];
unsigned long b = mod_args[0] ^ mod_args[2] ^ mod_args[4] ^ mod_args[6];
Run Code Online (Sandbox Code Playgroud)
而不是通过concat获得结果两件:
unsigned long long result = (((unsigned long long)a) << 32) | b;
Run Code Online (Sandbox Code Playgroud)