我应该担心在指针铸造对齐? [英] Should I worry about the alignment during pointer casting?

查看:138
本文介绍了我应该担心在指针铸造对齐?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的项目,我们有一张code是这样的:

  //原始数据由4个整数
unsigned char型数据[16];
INT I1,I2,I3,I4;
I1 = *((为int *)的数据);
I2 = *((为int *)(数据+ 4));
I3 = *((为int *)(数据+ 8));
I4 = *((为int *)(数据+ 12));
 

我跟我的技术主管,这code可能无法移植,因为它试图投无符号字符* INT * 通常具有更严格对齐要求。但是,技术主管说,没关系,大多数编译器仍然铸造后相同的指针值,我可以只写code这样的。

要坦率地说,我真的不相信。经过研究,我发现一些人对使用指针件类似上面,例如,<一的href="https://www.securecoding.cert.org/confluence/display/cplusplus/EXP36-CPP.+Do+not+convert+pointers+into+more+strictly+aligned+pointer+types">here这里

因此​​,这里是我的问题:

  1. 铸造一个真正的项目之后,是不是真的安全取消引用指针?
  2. 有C风格的铸件之间有什么区别和 reinter pret_cast
  3. 有C和C ++?
  4. 有什么区别
解决方案
  

1。铸造一个真正的项目之后,是不是真的安全取消引用指针?

如果指针恰好没有正确对齐它真的会导致问题。我亲眼所见和固定造成的铸造的char * 来一个更严格对齐类型总线错误。即使你没有得到一个明显的错误,你可以有不太明显的问题,如性能下降。严格按照标准,以避免UB是,即使你没有立即看到任何问题,是个好主意。 (和code是打破规则是严格走样规则第3.10 / 10)

一个更好的替代方法是使用的std ::的memcpy()的std :: memmove与如果缓冲区重叠(或更好,但 bit_cast&LT;&GT;()

  unsigned char型数据[16];
INT I1,I2,I3,I4;
的std ::的memcpy(安培; I1,数据的sizeof(INT));
的std ::的memcpy(安培; I2,数据+ 4的sizeof(INT));
的std ::的memcpy(安培;酷睿i3,数据+ 8的sizeof(INT));
的std ::的memcpy(安培; I4,数据+ 12,的sizeof(INT));
 

一些编译器的工作比别人更努力,以确保字符数组排列更严格的比必要的,因为程序员常常犯了这个错误,但。

 的#include&LT; cstdint&GT;
#包括&LT;所属类别&GT;
#包括&LT;的iostream&GT;

模板&LT; typename的T&GT;无效check_aligned(无效* P){
    性病::法院&LT;&LT; P&LT;&LT; 是&其中;&其中;
      (0 ==(reinter pret_cast&LT;的std ::使用intptr_t&GT(P)%alignof(T)):NOT)&LT;&LT;
      对齐的类型&LT;&LT; typeid的(T)。名称()&LT;&LT; '\ N';
}

无效foo1(){
    所以char a;
    炭B〔的sizeof(INT)];
    check_aligned&LT; INT&GT;(二); //未对齐铛
}

的struct {
    所以char a;
    炭B〔的sizeof(INT)];
};

无效foo2的(){
    šš;
    check_aligned&LT; INT&GT;(S.B); //未对齐的叮当声和MSVC
}

šš;

无效foo3(){
    check_aligned&LT; INT&GT;(S.B); //未对齐铛,MSVC和海湾合作委员会
}

诠释的main(){
    foo1();
    foo2的();
    foo3();
}
 

http://ideone.com/FFWCjf

  

2。有没有C风格的铸造和reinter pret_cast?

有什么区别

这要看情况。 C风格的类型转换操作取决于所涉及的类型的不同的事情。指针类型之间的C风格的铸件会导致同样的事情作为一个rein​​ter pret_cast;见§5.4的显式类型转换(转换符号)的节和第5.2.9-11。

  

3。有C和C ++?

有什么区别

不应该有,只要你正在处理的是合法的C型。

In my project we have a piece of code like this:

// 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));

I talked to my tech lead that this code may not be portable since it's trying to cast a unsigned char* to a int* which usually has a more strict alignment requirement. But tech lead says that's all right, most compilers remains the same pointer value after casting, and I can just write the code like this.

To be frank, I'm not really convinced. After researching, I find some people against use of pointer castings like above, e.g., here and here.

So here are my questions:

  1. Is it REALLY safe to dereference the pointer after casting in a real project?
  2. Is there any difference between C-style casting and reinterpret_cast?
  3. Is there any difference between C and C++?

解决方案

1. Is it REALLY safe to dereference the pointer after casting in a real project?

If the pointer happens to not be aligned properly it really can cause problems. I've personally seen and fixed bus errors caused by casting a char* to a more strictly aligned type. Even if you don't get an obvious error you can have less obvious issues like slower performance. Strictly following the standard to avoid UB is a good idea even if you don't immediately see any problems. (And the rule the code is breaking is the strict aliasing rule, § 3.10/10)

A better alternative is to use std::memcpy() or std::memmove if the buffers overlap (or better yet bit_cast<>())

unsigned char data[16];
int i1, i2, i3, i4;
std::memcpy(&i1, data     , sizeof(int));
std::memcpy(&i2, data +  4, sizeof(int));
std::memcpy(&i3, data +  8, sizeof(int));
std::memcpy(&i4, data + 12, sizeof(int));

Some compilers work harder than others to make sure char arrays are aligned more strictly than necessary because programmers so often get this wrong though.

#include <cstdint>
#include <typeinfo>
#include <iostream>

template<typename T> void check_aligned(void *p) {
    std::cout << p << " is " <<
      (0==(reinterpret_cast<std::intptr_t>(p) % alignof(T))?"":"NOT ") <<
      "aligned for the type " << typeid(T).name() << '\n';
}

void foo1() {
    char a;
    char b[sizeof (int)];
    check_aligned<int>(b); // unaligned in clang
}

struct S {
    char a;
    char b[sizeof(int)];
};

void foo2() {
    S s;
    check_aligned<int>(s.b); // unaligned in clang and msvc
}

S s;

void foo3() {
    check_aligned<int>(s.b); // unaligned in clang, msvc, and gcc
}

int main() {
    foo1();
    foo2();
    foo3();
}

http://ideone.com/FFWCjf

2. Is there any difference between C-style casting and reinterpret_cast?

It depends. C-style casts do different things depending on the types involved. C-style casting between pointer types will result in the same thing as a reinterpret_cast; See § 5.4 Explicit type conversion (cast notation) and § 5.2.9-11.

3. Is there any difference between C and C++?

There shouldn't be as long as you're dealing with types that are legal in C.

这篇关于我应该担心在指针铸造对齐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆