我应该在Visual Studio中转换void ** return

时间:2017-09-06 08:42:51

标签: c visual-studio-2008 casting

我使用visual studio 9.0(2008)编译了一些代码。

表现如预期,但是当我用一些手工制作分配一些2D数组时 函数,Visual-Studio生成一些C4133警告:

void ** alloc_2d(int w, int h, size_t type_size);
void free_d2(void ** mem);

int main (void)
{        
    float ** data;

    /* Here is generated a C4133 warning:
       "incompatible type from void ** to float **" */
    data = alloc_2d(100, 100, sizeof **data);

    /* do things with data */

    /* free data */
    free_2d(data);

    return 0;
}

我理解为什么会产生这个警告,但我想知道我该怎样做以使它安静。

我该怎么办?

  • 忍受警告?
  • 禁用警告(我认为危险)?
  • 禁用alloc_2d调用周围的警告(某些特定于的宏) 视觉工作室)?
  • 强制转换函数(但是[Do I cast the result of malloc?

第二个问题:

  • 新的/其他编译器是否意识到这种演员?

void**后面隐藏着两个数组:一个用于存储我需要连续的所有数据,另一个用于浏览不同的数据。

实现看起来像(我删除了错误检查)

void **alloc_2D_array(int w, int h, size_t size)
{
    void ** mem = malloc(w * sizeof *mem);
    *mem = malloc(w*h*size);
    for (i = 1; i < w; ++i)
    {
        mem[i] = (void*)((char*)mem[0] + i*w*size);
    }
    return mem;
}

2 个答案:

答案 0 :(得分:3)

从签名中,我假设你的功能大致是这样实现的(加上错误检查我为了简洁起见而遗漏了):

void **alloc_2d(int w, int h, size_t type_size)
{
    void **pointers = malloc(h * sizeof *pointers);
    for (size_t i = 0; i < h; ++i)
    {
        pointers[i] = malloc(w * type_size);
    }
    return pointers;
}

对此有一些评论:

  • 此函数的结果是 2d数组,但是指向数组的指针数组。它可以在某种程度上类似于真正的2d数组,但带来一些开销。一个真正的二维数组将是一个大小为w * h * type_size的连续块。
  • 此代码实际上是不安全的,当您将从其返回的void **转换为float **时,可能会调用未定义的行为。这是因为不能保证指向不同类型的指针具有相同的表示 - 它们甚至可以具有不同的大小。另见Are there any platforms where pointers to different types have different sizes?。通过将void **转换为float **,您将void * 数组视为和数组float *。虽然在典型的现代PC平台上可能还不错,但可能完全错误

也就是说,你可以通过简单地让函数返回void *而不是void **来避免强制转换,但这只会隐藏问题:void * 泛型指针类型,编译器将允许隐式转换为任何其他指针类型,但您仍然使用错误的指针类型访问您的void *数组。

我建议改为分配一个平面阵列并手动计算偏移量,如下所示:

size_t rows = 100;
size_t cols = 100;
float *data = malloc(cols * rows * sizeof *data);

data[cols*5 + 3] = 1.41;
// ...

free(data);

作为替代方案,您可以使用可变长度数组(在C99中必须使用,可选但在C11中几乎总是支持 - 可能不支持Microsoft ....)来动态分配实数 2d数组

size_t rows = 100;
size_t cols = 100;
float (*data)[cols] = malloc(rows * sizeof *data);

data[5][3] = 1.41;
// ...
free(data);

答案 1 :(得分:2)

C中的通用指针类型是void* not 表示void**也是通用指针类型,规则不会递归应用。

相反,从void**float**或从另一种方式转换是无效的指针转换。它们不是兼容类型 - 编译器必须发出诊断消息。忽略警告可能会导致数据错位或严重的别名问题 - 无论是哪种情况都会出现错误。

  

我该怎么办?

修复代码,使其不包含禁止的指针转换。

  

新的/其他编译器是否意识到这种演员?

自C的第一次标准化以来,这条特殊的规则没有改变。

关于如何修复代码......你不应该这样做。您应该从头开始重写它,以便它分配数组而不是“基于指针的查找表”。没有明显的理由说明为什么你会从这里的查找表中受益,但是你应该避免它的许多原因。

此外,如果使用指向VLA的指针,您的代码将更易读。

有关如何正确执行此操作的示例,请参阅Correctly allocating multi-dimensional arrays。(答案最底部的代码示例)。