Указатель на массив из N элементов против указателя на массив или на первый элемент массива - PullRequest
1 голос
/ 18 июня 2020

У меня есть устаревший код, в котором одна функция возвращает указатель на массив из 8 uint8_t, а другая принимает указатель на uint8_t, который указывает на массив.

typedef uint8_t (*u8_8)[8]; //hope this typedef pointer to array of 8 uint8

позволяет сказать, что реализация first выглядит как следует за

u8_8 get(void)
{
  static uint8_t ar[8];
  return &ar;
}

вторая функция берет uint8_t * и делает с ним немного c

void second(uint8_t *data)
{
  //...
}

Мой вопрос. Мои преобразования верны?

//...
uint8_t *p = *(get());
second(p);

Предупреждений компилятора нет, но я просто хочу убедиться. Спасибо и наилучшими пожеланиями. :)

Ответы [ 3 ]

0 голосов
/ 18 июня 2020

У меня вопрос. Правильно ли мои преобразования?

//...
uint8_t *p = *(get());
second(p);

Ваше преобразование допустимо, потому что выражение * (get ()) имеет тип uint8_t [8] и используется в качестве инициализатора, оно преобразуется в указатель на первый элемент заостренного массива.

Возврат из функции объекта типа uint8_t (*u8_8)[8] вместо объекта типа uint8_t * имеет смысл, потому что вы можете определить количество элементов заостренного массива. Фактически, возвращаемая функция предоставляет два типа информации: адрес массива и количество элементов в массиве.

Например, если у вас есть функция, которая объявлена ​​как

void func( uint8_t *a, size_t n );

, вы можете легко вызвать ее для возвращаемого массива с указателями из функции, например

u8_8 ptr = get();

func( *ptr, sizeof( *ptr ) / sizeof( **ptr ) );

Вот демонстрационная программа.

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

typedef uint8_t (*u8_8)[8];

u8_8 get(void)
{
  static uint8_t ar[8] = "12345678";
  return &ar;
}

void out( const uint8_t *a, size_t n )
{
    for ( size_t i = 0; i < n; i++ )
    {
        putchar( a[i] );
    }

    putchar( '\n' );
}

int main(void) 
{
    u8_8 ptr = get();

    out( *ptr, sizeof( *ptr ) / sizeof( **ptr ) );

    return 0;
}

Ее результат

12345678
0 голосов
/ 18 июня 2020

" Мои преобразования верны? Предупреждений компилятора нет, но я просто хочу убедиться. "

Да, все правильно. Нет синтаксических c ошибок и не вызывается неопределенное поведение, потому что все (указательные) типы совпадают в соответствующих выражениях.


u8_8 get(void)
{
  static uint8_t ar[8];
  return &ar;
}
return &ar;

&ar имеет тип uint8_t (*)[8]. Обратите внимание, когда вы используете return ar;, ar распадается на указатель на свой первый элемент, введите uint8_t *; но поскольку к нему применяется оператор &, этого не происходит. Вместо этого он получает указатель на весь массив uint8_t (*)[8].


*(get())

Выражение get() имеет тип uint8_t (*)[8], соответствующий типу возвращаемого &ar в вызываемой функции get().

Разыменование указателя на массив из 8 uint8_t *(get()) с помощью оператора *, тип uint8_t (*)[8] получает массив из 8 элементов uint8_t, тип uint8_t [8]. В другой раз массив распадается до указателя на первый его элемент, введите uint_8t *, который идеально соответствует p в вызывающем, поэтому присвоение верное.

second(p);

second ожидает аргумент типа uint8_t *, который соответствует p в вызывающей стороне.


Ваш код можно упростить до:

uint8_t* get (void)
{
    static uint8_t ar[8];
    return ar;
}

void second (uint8_t *data)
{
    //...
}

....

int main (void)
{
    uint8_t *p = get();
    second(p);
}

Примечание: typedef из typedef uint8_t (*u8_8)[8]; теперь полностью ненужен и избыточен, но вам нужно изменить тип возвращаемого значения get на uint8_t *, а также соответствующим образом изменить инициализацию p в вызывающей программе.


Если вы этого не сделаете Вам не нужен указатель p в вызывающей стороне, вы даже можете использовать возвращаемое значение get() непосредственно в качестве аргумента для second():

second(get());
0 голосов
/ 18 июня 2020

Функция get возвращает указатель на массив из 8 байтов без знака.

Если разыменовать этот указатель, вы получите массив, на который он указывает.

Этот массив будет в свою очередь распадается на указатель (на uint8_t, т.е. uint8_t *).

Это именно то, что ожидает функция second.

Фактически, вы можете сократить весь вещь в один оператор:

second(*get());

С учетом сказанного, на самом деле нет необходимости для get возвращать указатель на массив. Вместо этого он мог бы вернуть сам массив, позволяя ему распасться до указателя на свой первый элемент:

uint8_t *get()
{
    static uint8_t ar[8];
    return ar;
}

...

uint8_t *o = get();
second(p);

// Or: second(get());
...