在C

时间:2018-09-26 03:49:24

标签: c arrays pointers language-lawyer dereference

根据我对C的理解,您可以将指针变量和数组变量视为等效变量,因为它们最终都是指针(一个指向本地函数堆栈,另一个指向内存中的任意随机点)。

我通常在需要返回指针时将指针传递给指针(例如char ** pvar),因此我可以看出将其传递回解引用的本地数组的意义不大,因为您可以t更改变量的位置。

我的期望是,如果我尝试这样做,编译器会让我这样做,然后在尝试设置返回指针值时出现段错误或崩溃。

但是,当尝试取消引用数组类型(&array)时,编译器会有用地生成有关使用不兼容类型的警告,然后将指针传递给数组,从接收函数的角度来看,本质上会失去一种间接级别。

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

void ptrptr(uint32_t** dptr)
{
    printf("%x, %x\n",  dptr, *dptr);
}

void oneptr(uint32_t* ptr)
{
    printf("%08x, %x\t",  ptr, *ptr);
    ptrptr(&ptr);
}

int main()
{
    uint32_t array[] = {1};
    uint32_t *ptr = calloc(1, sizeof( uint32_t));
    ptr[0] = 3;
    oneptr(ptr);    /* OK, passes an (uint32_t *)  */
    oneptr(array);  /* OK, passes an (uint32_t *)  */
    ptrptr(&ptr);   /* OK, passes an (uint32_t **) */
    ptrptr(&array); /* ??, passes an (uint32_t *)  */
    return 0;
}

编译它会给我警告

cc     test.c   -o test
test.c: In function ‘main’:
test.c:24:9: warning: passing argument 1 of ‘ptrptr’ from incompatible pointer type [-Wincompatible-pointer-types]
  ptrptr(&array);
     ^
test.c:5:6: note: expected ‘uint32_t ** {aka unsigned int **}’ but argument is of type ‘uint32_t (*)[1] {aka unsigned int (*)[1]}’
 void ptrptr(uint32_t** dptr)
      ^~~~~~
0061a008, 3     7ebfa144, 61a008
7ebfa154, 1     7ebfa144, 7ebfa154
7ebfa150, 61a008
7ebfa154, 1

当我使用gcc,clang和cl进行编译时,会得到相同的结果,因此,我非常有信心这不是编译器错误。那么问题是,为什么当我尝试取消引用数组时,C为什么会静默传递指针(uint32_t*)而不是指针(uint32_t**)指针?

2 个答案:

答案 0 :(得分:3)

  

然后的问题是,当我尝试取消引用数组时,为什么C静默传递指针(uint32_t*)而不是指针(uint32_t**)的指针?

  • 不是。

  • C正在传递一个指向一个uint32_t(uint32_t(*)[1])数组的指针。

  • 它是指向一个uint32_t数组的指针,因为它是一个uint32_t数组,并且您有指向它的指针。

  • 这不是沉默。您会收到一个编译器警告,提示“嘿,这是错误的指针类型!”。您认为这是什么?

    test.c: In function ‘main’:
    test.c:24:9: warning: passing argument 1 of ‘ptrptr’ from incompatible pointer type [-Wincompatible-pointer-types]
      ptrptr(&array);
         ^
    test.c:5:6: note: expected ‘uint32_t ** {aka unsigned int **}’ but argument is of type ‘uint32_t (*)[1] {aka unsigned int (*)[1]}’
     void ptrptr(uint32_t** dptr)
    
  • 您没有取消引用数组。您正在创建一个指向数组的指针,将其转换为错误的指针类型,然后取消引用。

  • 之所以给您数字1,是因为指向数组的指针实际上指向的地址与指向数组中第一件事的指针相同。虽然,这是一种不同类型的指针,这意味着++之类的东西工作方式不同,但是随后您将其转换为相同类型的指针,因此您的代码不会注意到。

答案 1 :(得分:0)

  

然后的问题是,当我尝试取消引用数组时,为什么C会静默传递指针(uint32_t *)而不是指针(uint32_t **)的指针?

这不是沉默,它给了您警告。 C标准没有提到术语“错误”和“警告”,而是提到了诊断消息。要遵循C标准,只要编译器向程序员显示诊断消息就足够了。

如果您希望使用gcc或clang违反C标准时出错而不是警告,则必须使用-std=c11 -pedantic-errors进行编译。

关于代码为何不正确,&array以数组指针uint32_t(*)[1]的形式给出数组的地址。此类型与uint32_t**不兼容。未指定运行包含C标准约束违例的程序将不会发生的事情:它是未定义的行为。没有段故障或崩溃的保证,这些只是未定义行为的许多潜在结果中的两个。