将双指针传递给 C 和 C++ 中的函数的区别

Difference in passing a double pointer to a function in C and C++

在 parseFunc() 中,如果我通过传递 &tIpArray 调用 loadFunc(),它在使用 C 作为编译时编译正常(在 onlinegdb.com),但在更高版本的 C 编译器(gcc-bin/4.9.4/gcc) 在工作。

工作中的错误类似于我在onlinegdb 中使用C++ 语言进行编译时看到的错误。谁能告诉我为什么 4.9.4 gcc C 编译器不喜欢 & 以及处理这个问题的正确方法是什么?

/******************************************************************************

Welcome to GDB Online.
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby, 
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
Code, Compile, Run and Debug online from anywhere in world.

*******************************************************************************/
#include <stdio.h>
#include <stdlib.h>

typedef struct _MyStruct
{
    char string[72];
}MyStruct;

int loadFunc(MyStruct** ipData, int counter)
{
    MyStruct **currentVal = ipData;

    MyStruct *ipPtr = NULL;

    printf("%p\n", currentVal);

    for(int i=0; i<counter; i++)
    {
        ipPtr = currentVal[i];
        printf("Line-%d - %s - %p\n", i+1, ipPtr->string, ipPtr);
    }
}

int parseFunc()
{
        MyStruct*   tIPArray[3];

        for(int i=0; i< 3; i++)
        {
            tIPArray[i] = 0;
            tIPArray[i] = (MyStruct*) calloc(1, sizeof(MyStruct));
            snprintf(tIPArray[i]->string, 72, "Test-String-%d", i+101);         
        }        

        for(int i=0; i<3; i++)
        {
            printf("Line-%d %p-%p- %s\n", i+1, &tIPArray[i], tIPArray[i], tIPArray[i]->string);
        }

        // call the load/ print loadFunc
        loadFunc(&tIPArray, 3);
}

int main()
{
    printf("Hello World\n");
    parseFunc();
    return 0;
}

Below is the error I get at work

error: passing argument 1 of 'loadFunc' from incompatible pointer type [-Werror]
   loadFunc(&tIPArray, 3);
note: expected 'struct MyStruct **' but argument is of type 'struct MyStruct * (*)[(sizetype)((int)((short unsigned int)getMaxAddressObjects() / 4u))]'
 int loadFunc(MyStruct **ipData, int counter)

在 onlinegdb.com 中将其构建为 C++ 文件时出现以下错误

main.cpp: In function ‘int parseFunc()’:
main.cpp:49:38: error: cannot convert ‘MyStruct * (*)[3] {aka MyStruct * (*)[3]}’ to ‘MyStruct ** {aka MyStruct **}’ for argument ‘1’ to ‘int loadFunc(MyStruct **, int)’
     loadFunc(&tIPArray, 3);

这个声明...

        MyStruct*   tIPArray[3];

tIPArray 声明为 3 MyStruct * 的数组。因此,&tIPArray是指向这样一个数组的指针,它的类型是MyStruct *(*)[3],正如错误信息所说。这与 MyStruct ** 不同,后者是函数参数的预期类型。

您可以改为传递指向第一个元素的显式指针...

        loadFunc(&tIPArray[0], 3);

...但是省略 & 会更符合习惯,因为数组到指针(数组的 "decay")的普通转换会生成正确类型和值的指针:

        loadFunc(tIPArray, 3);

也许用typedef MyStruct* StrPtr;会更清楚。然后你的例子变成:

void foo(StrPtr* bar);

StrPtr array[4];

首先,让我们看一下这个调用:

foo(array);

数组的类型是 StrPtr[4],不是 StrPtr*。理想情况下,这会调用 foo(StrPtr bar[4]) 但没有这样的功能。下一个最佳匹配是数组可以衰减到指向其元素的指针 = StrPtr* 幸运的是有 foo(StrPtr* bar) 函数所以调用有效。

现在,这个表达式的类型是什么?

&array;

好吧,数组也是 StrPtr[4] 类型,所以这一定是指向该类型的指针 = StrPtr(*)[4]。与函数指针相同的 "weird" 语法。

最后,接这个电话:

foo(&array);

我们现在知道这会调用 foo(StrPtr(*bar)[4]) 但同样没有这样的函数。那么编译器能做什么呢? &array 不是一个数组,它是一个指针,指针不能衰减到任何东西。嗯,现在怎么办?好吧,在 C 中,任何类型的指针都可以传递给另一个指针。取消引用这样的指针是另一回事。因此,此调用有效并调用 foo(StrPtr* bar),因为没有其他候选者。成功?不,任何体面的编译器都应该对此发出警告,甚至更好地使用 -Wincompatible-pointer-types 将这些警告转化为错误,甚至像您所做的那样使用 -Werror 禁止所有警告。

所以,要点是正确的调用是 foo(array);