【问题标题】:Pointer arithmetic on void* pointersvoid* 指针的指针运算
【发布时间】:2016-06-27 07:13:46
【问题描述】:

我正在使用 CUDA API / cuFFT API。为了将数据从主机移动到 GPU,我使用了 cudaMemcpy 函数。我正在使用它,如下所示。 len 是 dataReal 和 dataImag 上的元素数量。

void foo(const double* dataReal, const double* dataImag, size_t len)
{
    cufftDoubleComplex* inputData;
    size_t allocSizeInput = sizeof(cufftDoubleComplex)*len;
    cudaError_t allocResult = cudaMalloc((void**)&inputData, allocSizeInput);

    if (allocResult != cudaSuccess) return;

    cudaError_t copyResult;

    coypResult = cudaMemcpy2D(static_cast<void*>(inputData),
                              2 * sizeof (double),
                              static_cast<const void*>(dataReal),
                              sizeof(double),
                              sizeof(double),
                              len,
                              cudaMemcpyHostToDevice);

    coypResult &= cudaMemcpy2D(static_cast<void*>(inputData) + sizeof(double),
                              2 * sizeof (double),
                              static_cast<const void*>(dataImag),
                              sizeof(double),
                              sizeof(double),
                              len,
                              cudaMemcpyHostToDevice);

    //and so on.
}

我知道,对 void 指针的指针运算实际上是不可能的。第二个 cudaMemcpy2D 仍然有效。我仍然收到编译器的警告,但它可以正常工作。

我尝试使用 static_cast 但这不起作用,因为 cuffDoubleComplex* 不能静态转换为 char*。

我有点困惑,为什么第二个 cudaMemcpy 在 void 上使用指针算术正在工作,据我所知它不应该。编译器是否隐式假设 void* 后面的数据类型是一个字节长?

我应该在那里改变一些东西吗?例如使用 reinterpret_cast(inputData) ?

在分配过程中,我使用的是旧的 C 风格 (void**) 演员表。我这样做是因为我得到“从 cufftDoubleComplex** 到 void** 的无效 static_cast”。还有其他方法可以正确执行此操作吗?

仅供参考:Link to cudaMemcpy2D Doc

Link to cudaMalloc Doc

【问题讨论】:

  • 尝试static_cast&lt;void*&gt;(&amp;(inputData-&gt;y))(而不是+ ...)并使用sizeof(cufftDoubleComplex)而不是2 * sizeof(cufftDoubleComplex)(即使是相同的值,第一个更通用)。
  • 不清楚为什么你觉得需要投射任何东西。 cudaMalloc 不要求您转换为 void **cudaMemcpy2D 也不要求您转换为 void *
  • cudaMalloc 需要一个 void** 而 cudaMemcpy2D 需要一个 void*。我知道一个事实,它们都适用于字节而不是类型。我实际上想要一个 char* 但这不是 CUDA API 想要我做的。
  • 你不需要做任何转换。 (试试看。)只需将您计算的任何指针或计算指针(例如&amp;(double *))传递给cudaMalloc。同样对于cudaMemcpy(即double *)即使您要使用强制转换(再次,不必要)您应该首先执行所有指针运算,无论是相关类型(例如@987654336 @) 然后作为最后一步。这将完全避免使用void * 进行任何指针运算。
  • 在这种情况下,指针是隐式转换的,不是吗?老实说,我更喜欢手动操作,以便在我的代码中清楚地显示所有类型,这样任何人看到它,都可以立即看到所做的事情。同时,在强制转换之前做算术确实是有意义的。

标签: c++ pointers cuda pointer-arithmetic


【解决方案1】:

您不能对void* 进行算术运算,因为指针上的算术运算是基于指向对象的大小(而sizeof(void) 并没有真正的意义)。

您的代码能够编译可能要归功于编译器扩展,该扩展将void* 上的算术运算视为char* 上的算术运算。

在您的情况下,您可能不需要算术运算,以下应该可以工作(并且更健壮):

coypResult &= cudaMemcpy2D(static_cast<void*>(&inputData->y),
                           sizeof (cufftDoubleComplex),

因为cufftDoubleComplex 很简单:

struct __device_builtin__ __builtin_align__(16) double2
{
    double x, y;
};

【讨论】:

  • 感谢您的建议。我也应该能够看到这一点,但我没有;-)。将尽快尝试此操作,并在有效时将您的答案标记为答案。干杯!
猜你喜欢
  • 2014-05-30
  • 1970-01-01
  • 2011-04-01
  • 1970-01-01
  • 2019-11-17
  • 1970-01-01
  • 2011-06-30
相关资源
最近更新 更多