我应该担心在指针铸造对齐?指针、担心

由网友(╰櫻花°)分享简介:在我的项目,我们有一张code是这样的://原始数据由4个整数unsigned char型数据[16];INT I1,I2,I3,I4;I1 = *((为int *)的数据);I2 = *((为int *)(数据+ 4));I3 = *((为int *)(数据+ 8));I4 = *((为int *)(数据...

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

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

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

调节指针对齐

要坦率地说,我真的不相信。经过研究,我发现一些人对使用指针件类似上面,例如,here这里 。

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

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

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

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

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

  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< cstdint>
#包括<所属类别>
#包括<的iostream>

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

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

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

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

šš;

无效foo3(){
    check_aligned< INT>(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:

Is it REALLY safe to dereference the pointer after casting in a real project? Is there any difference between C-style casting and reinterpret_cast? 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.

阅读全文

相关推荐

最新文章