разыменовывать локальный массив в C - PullRequest
0 голосов
/ 26 сентября 2018

Насколько я понимаю, вы можете рассматривать переменную-указатель и переменную-массив как эквивалентные, поскольку в конечном итоге они оба являются указателями (один для локального стека функций, другой для любой случайной точки в памяти).

Обычно я передаю указатель на указатель (например, char ** pvar), когда мне нужно вернуть указатель, поэтому я вижу, как бессмысленно передавать его обратно в локальный массив с разыменованными ссылками, поскольку вы не можете изменитьПоложение переменной.

Я ожидал бы, что если я попробую это сделать, компилятор разрешит мне это сделать, а затем при попытке установить значение возвращаемого указателя произойдет сбой или сбой.

Однако при попытке разыменования типа массива (и массива) компилятор предупреждает об использовании несовместимых типов, а затем передает указатель на массив, фактически теряя один уровень косвенности с точки зрения принимающей функции.

#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 голосов
/ 26 сентября 2018

Тогда возникает вопрос, почему C молча передает указатель (uint32_t *) вместо указателя на указатель (uint32_t **), когда я пытаюсь разыменовать массив?

Это не молчит, это дало вам предупреждение.Стандарт C не упоминает термины «ошибки» и «предупреждения», но говорит о диагностических сообщениях.Чтобы следовать стандарту C, достаточно, чтобы компилятор показывал диагностическое сообщение программисту.

Если вы хотите получить ошибку вместо предупреждения о нарушениях стандарта C с помощью gcc или clang, вы должны скомпилировать с -std=c11 -pedantic-errors.

Что касается того, почему код не верен, &array дает адрес массива в виде указателя массива, uint32_t(*)[1].Этот тип не совместим с uint32_t**.Что произойдет, если вы запустите программу, несмотря на то, что она содержит стандартное нарушение ограничения C, не указано: это неопределенное поведение.Нет гарантии ошибки сегмента или сбоя, это только два из многих возможных результатов неопределенного поведения.

0 голосов
/ 26 сентября 2018

Тогда возникает вопрос: почему 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, заключается в том, что указатель на массивфактически указывает на тот же адрес, что и указатель на первую вещь в массиве.Хотя это другой тип указателя, что означает, что такие вещи, как ++, работают по-разному, но затем вы конвертируете его в указатель того же типа, чтобы ваш код не заметил.

...