我们需要将int**转换为void**,可以使用reinterpret_cast。然而,它在技术上是否被C++标准所允许,或者我们是否处于未定义行为的领域?
int**
void**
reinterpret_cast
用例
使用Nvidia库时,我们需要使用指针到指针:
cudaMalloc(void** ptr, size_t size);
一个典型的解决方案是:
int* p; cudaMalloc(reinterpret_cast<void**>(&p), 123);
niknxzdl1#
强制转换本身是允许的,但在标准的保证下实际上并不有用,因为任何对结果的非平凡使用最终都会导致未定义的行为。具体地说,如果alignof(void**) > alignof(int**),那么原始指针可能没有为void**适当地对齐,然后转换的结果将是未指定的,并且实际上任何对结果的使用都将导致未定义的行为。也就不可能转换回原始值。否则,转换、传递指针和转换回int**都是允许的。但是,通过void**访问(例如,将指针值写入提供的指针到指针)将是一个别名冲突,因为void*不能别名int*。因此,如果cudaMalloc访问指针而没有首先转换回int**,则行为未定义。这就是C++标准在这方面的全部内容。考虑到你似乎是专门询问CUDA,它的规范当然可以提供额外的保证。这在实践中可能会非常重要。然而,如果你认为这是一个类似malloc的通用实现,那么就不可能编写这个函数来让这个使用模式定义行为,因为这个函数不知道它必须首先转换回哪个指针类型。这不仅仅是理论上的问题。许多编译器确实利用这种类型的UB来进行优化。可以在没有混叠违规和UB的情况下实现的正确模式应该是这样的
alignof(void**) > alignof(int**)
void*
int*
cudaMalloc
malloc
void* p_temp; cudaMalloc(&p_temp, 123); auto p = static_cast<int*>(p_temp);
1条答案
按热度按时间niknxzdl1#
强制转换本身是允许的,但在标准的保证下实际上并不有用,因为任何对结果的非平凡使用最终都会导致未定义的行为。
具体地说,如果
alignof(void**) > alignof(int**)
,那么原始指针可能没有为void**
适当地对齐,然后转换的结果将是未指定的,并且实际上任何对结果的使用都将导致未定义的行为。也就不可能转换回原始值。否则,转换、传递指针和转换回
int**
都是允许的。但是,通过void**
访问(例如,将指针值写入提供的指针到指针)将是一个别名冲突,因为void*
不能别名int*
。因此,如果cudaMalloc
访问指针而没有首先转换回int**
,则行为未定义。这就是C++标准在这方面的全部内容。考虑到你似乎是专门询问CUDA,它的规范当然可以提供额外的保证。这在实践中可能会非常重要。
然而,如果你认为这是一个类似
malloc
的通用实现,那么就不可能编写这个函数来让这个使用模式定义行为,因为这个函数不知道它必须首先转换回哪个指针类型。这不仅仅是理论上的问题。许多编译器确实利用这种类型的UB来进行优化。可以在没有混叠违规和UB的情况下实现的正确模式应该是这样的