相关疑难解决方法(0)

严格的指针别名:针对特定问题的任何解决方案?

我有一个问题,破坏了严格的指针别名规则.我有一个T来自模板的类型和一些Int相同大小的整数类型(如同sizeof).我的代码基本上做了以下事情:

T x = some_other_t;
if (*reinterpret_cast <Int*> (&x) == 0)
  ...
Run Code Online (Sandbox Code Playgroud)

因为T是一些可以有构造函数的任意(除了大小限制)类型,我不能建立T和的联合Int.(这仅在C++ 0x中允许,甚至GCC也不支持).

有没有什么办法可以重写上面的伪代码来保留功能并避免破坏严格的别名规则?注意,这是一个模板,我无法控制T或重视some_other_t; 赋值和后续比较确实发生在模板化代码中.

(对于记录,如果T包含任何位字段,上面的代码在GCC 4.5上开始打破.)

c++ generics strict-aliasing reinterpret-cast type-punning

8
推荐指数
1
解决办法
770
查看次数

打破严格的走样和生活来讲述它?

我试图在我在C++ 11中编写的同一个应用程序中使用两个库LIBSVMLIBLINEAR.LIBSVM和LIBLINEAR都在基本上是基于行的稀疏矩阵表示中输入它们:存在节点结构

struct svm_node
{
    int index;
    double value;
};
Run Code Online (Sandbox Code Playgroud)

稀疏矩阵本身就是struct svm_node **,每行都是a struct svm_node *,行终止index = -1.调用此结构的LIBLINEAR版本feature_node并具有相同的定义.虽然LIBSVM和LIBLINEAR由同一作者写的,svm.hlinear.h,因此struct svm_nodestruct feature_node是没有丝毫关系.

在某些情况下,我想创建一个内核SVM模型(仅由LIBSVM实现)和一个逻辑回归模型(仅由LIBLINEAR实现)我的数据.数据集传递给它们各自的库---在二进制级别上,相同的---稀疏矩阵表示,可能非常大,我宁愿避免memcpy()全部.一个简单的reinterpret_cast<feature_node **>(svm_node_ptr_ptr_variable)似乎做得很好.

我也在-flto发布版本中使用LLVM的完整程序优化(),因此我希望确保代码不会以不可预测的方式进行优化.

有什么办法型双关语svm_node **feature_node **避免可能的(当前或未来)编译器优化导致的任何破损?__attribute__((__may_alias__))在这里有帮助,如果有,我应该如何使用它?


如果__attribute__((__may_alias__))只对类型有意义,那么如果我创建了自己的struct和指向结构的指针,它是否有效

struct __attribute__((__may_alias__)) SparseElement {
    int index;
    double value;
};
typedef SparseRow SparseElement * __attribute__((__may_alias__));
Run Code Online (Sandbox Code Playgroud)

然后将retinterpret_casted 传递SparseRow * …

c++ strict-aliasing type-punning c++11

7
推荐指数
1
解决办法
196
查看次数

easy struct inheritance&pseudo-polymorphism vs strict aliasing

如果有人回答我的问题,请不要告诉我使用C++.

所以,我在C中创建了一个使用面向对象方法的小型库.我选择在C中使用两种主要的继承方法中较不常见的方法:将基类型的成员复制到派生类型的开头.像这样的东西:

struct base {
  int a;
  int b;
  char c;
};

struct derived {
  int a;
  int b;
  char c;
  unsigned int d;
  void (*virtual_method)(int, char);
};
Run Code Online (Sandbox Code Playgroud)

这种方法不如另一种方法(基类型的实例作为派生类型的第一个成员)受欢迎,因为

  1. 从技术上讲,没有标准保证基础和派生结构的第一个共同成员将具有相同的抵消.但是,除了其中一个结构被打包而另一个结构没有被打包的情况之外,它们将在大多数(如果不是全部)已知编译器上具有相同的偏移量.
  2. 这种方法最严重的缺陷:它违反了严格的别名.将指向派生结构的指针强制转换为其基类型然后解除引用指针在技术上是未定义的行为.

但是,与其他方法相比,它也有其优点:

  1. 更少详细:访问已继承的派生结构的成员与访问尚未继承的结构相同,而不是转换为基类型,然后访问所需的成员;
  2. 这实际上是真正的继承而不是构成 ;
  3. 虽然可能需要一些预处理器滥用,但它与其他方法一样容易实现;
  4. 我们可以得到一个实际多重继承的半生不熟的形式,我们可以从几个基类型继承,但只能转换为其中一个.

我一直在寻找使我的库编译和使用强制执行严格别名(如gcc)的编译器正确工作的可能性,而无需用户手动关闭它.以下是我研究过的可能性:

  1. 工会.遗憾的是,由于以下几个原因,这些是禁忌:

    1. 详细程度回归!要遵循通过联合访问2个结构的第一个共同成员的标准规则,必须(从C99开始)明确使用联合来访问第一个共同成员.我们需要特殊的语法来访问联合中每种类型的成员!
    2. 空间.考虑一个继承层次结构.我们有一个类型,我们希望能够从每个派生类型转换为.我们希望为每种类型做到这一点.我看到的唯一可行的联合使用解决方案是整个层次结构的并集,它必须用于将派生类型的实例转换为基类型.它必须与整个层次结构中派生类型最多的一样大......
  2. 使用memcpy而不是直接解除引用(如此).这看起来是个不错的解决方案.但是,函数调用会产生开销,是的,再一次,冗长.据我所知,memcpy也可以通过将指向结构的指针强制转换为指针char然后解除引用来手动完成,如下所示:(member_type)(*((char*)(&struct_pointer->member))) = new_value;Gah,再次详述.好吧,这可以用宏包裹.但是,如果我们将指针转换为指向不兼容类型的指针,然后将其转换为char*并取消引用它,那么它仍然可以工作吗?像这样:(member_type)(*((char*)(&((struct incompatible_type*)struct_pointer)->member))) = new_value;

  3. 声明我们将要转换为的所有类型实例 …

c inheritance struct pointers strict-aliasing

6
推荐指数
1
解决办法
604
查看次数