Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Для новичков > как это работает?


Автор: LeonidPr 23.12.2014, 16:02
Добрый день. Разбираясь с ОСРВ RTX для микроконтроллеров наткнулся на некоторую для меня странность. Выделил её в такой вот код, который работает. но вот почему, я не до конца понимаю.
Код

#include <stdio.h>
#include <conio.h>

typedef unsigned long uint32_t;
typedef uint32_t ArrayType[4];

typedef struct {
    uint32_t field1;
    uint32_t field2;
    uint32_t field3;
    uint32_t field4;
} StructType, *p_StructType;

void func(void *Array) {
    static int i=0;
    p_StructType pStruct=(p_StructType)Array;

    pStruct->field1=i+1;
    pStruct->field2=i+2;
    pStruct->field3=i+3;
    pStruct->field4=i+4;
    i+=10;
};

int main() {
    ArrayType Array;

    func(Array);

    printf("%d\n",Array[0]);
    printf("%d\n",Array[1]);
    printf("%d\n",Array[2]);
    printf("%d\n",Array[3]);

    func(&Array);

    printf("%d\n",Array[0]);
    printf("%d\n",Array[1]);
    printf("%d\n",Array[2]);
    printf("%d\n",Array[3]);

    getch();
    return 0;
};

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

Автор: xvr 23.12.2014, 16:25
Array - это массив. При передаче его через формальный параметр (строка 28) он преобразуется в указатель на первй элемент (по семантике маасивов в С). Т.е. то же самое, что делается вручную в строке 35

Автор: LeonidPr 23.12.2014, 16:41
Цитата(xvr @  23.12.2014,  16:25 Найти цитируемый пост)
При передаче его через формальный параметр (строка 28) он преобразуется в указатель на первй элемент (по семантике маасивов в С).

Это-то понятно, я вот вот что не могу въехать...
переменная типа ArrayType - это константный указатель, когда я передаю аргумент в функцию таким образом
Код

func(&Array);

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

Автор: xvr 23.12.2014, 16:55
Цитата(LeonidPr @  23.12.2014,  16:41 Найти цитируемый пост)
то я сначала получаю указатель на Array (который сам является указателем),

Нет, не является. Массив есть своя собственная, отдельная сущность. Просто практически везде он автоматически преобразовывается в указатель на свой первый элемент. 
В данном случае автоматического преобразования не происходит, а явно берется указатель на массив (это одно из тех немногих мест в семантике С, где массив не пытается прикинуться указателем  smile ). 

PS. Второе место - оператор sizeof

Автор: LeonidPr 23.12.2014, 20:48
smile Вот как оказывается
Сейчас проверил еще раз, в первом сообщении я неправильно написал, действительно в обоих случаях передается указатель на первый элемент массива.
Но тогда возникает вопрос, что такое указатель на массив, чисто синтаксическое понятие?
т.к. сейчас провел такой эксперимент. Вот функция:
Код

void func2(uint32_t (*Param)[4]) {
        (*Param)[0]=1;
        (*Param)[1]=2;
        (*Param)[2]=3;
        (*Param)[3]=4;
};

Компилятор позволяет вызвать её только так:
Код

func2(&Array);

Хотя код генерирует, как будто я её вызывал так:
Код

func2(Array);


Добавлено через 4 минуты и 11 секунд
Мда, сначала задал вопрос, потом подумал. так же и получается как вы сказали, если массив это некое отдельное понятие, то все правильно, функция и получает указатель на этот именованный блок ячеек, суть указатель на первую... Спасибо за разъяснение, надо будет еще почитать по этой теме где-нибудь.

Автор: LeonidPr 24.12.2014, 10:24
м-м-м, забыл еще поинтересоваться, является ли эта особенность массивов implementation-defined, или это где-то описано в стандарте языка? сейчас ковыряю стандарт C++ 2003 , что-то пока не могу понять из чего следует такое поведение.

Автор: xvr 25.12.2014, 14:56
Цитата(LeonidPr @  23.12.2014,  20:48 Найти цитируемый пост)
Но тогда возникает вопрос, что такое указатель на массив, чисто синтаксическое понятие?

Указатель на масив - это указатель на его первый элемент. Получить указатель на сам массив, как целое, нельзя - нет такого понятия. Но есть ссылка на массив:
Код

#include <stdio.h>

template<size_t I>
void func( int (&arr)[I])
{
 printf("Array size: %d\n",I);
}

int main()
{
 int a[10];

 func(a);
}

Вывод:
Цитата

Array size: 10


Цитата(LeonidPr @  24.12.2014,  10:24 Найти цитируемый пост)
или это где-то описано в стандарте языка?

Описанно конечно. С++ 11 (драфт), раздел 8.3.4: Arrays

Автор: LeonidPr 21.1.2015, 09:58
Нашел интересную ссылку по теме, оказывается не у одного меня эта проблема возникла, даже в FAQ внесли.
http://c-faq.com/aryptr/index.html

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)