Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Инициализация структуры
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > Программирование
Страницы: 1, 2
Jenya7
Хотел немного схитрить, ну так, с краешку. Создал структуру
Код
typedef struct
{
    uint32_t menu_id;
    char *menu_text;
}MENU_ITEM;

typedef struct
{
    MENU_ITEM main_menu;
    MENU_ITEM *submenu;
}MENU;
Инициализирую
Код
MENU menu[] =
{
    {  { 1, "MENU1"},
       { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } }
    }
};
Компилятор ругается на уровне ворнинга
Цитата
(near initialization for 'menu[1].submenu') [enabled by default]
braces around scalar initializer [enabled by default]
excess elements in scalar initializer [enabled by default]
initialization makes pointer from integer without a cast [enabled by default]

причем если убираю скобки ругается на уровне ошибки.

Не хочет видеть как указатель на массив. Все так плохо или можно что то сделать?
AlexRayne
Цитата(Jenya7 @ Jul 20 2018, 15:25) *
Не хочет видеть как указатель на массив. Все так плохо или можно что то сделать?

все имено так плохо
делайте { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } } - отдельной константой.
код станет чуть менее красивым, но по моему - не сильно ухудшится. терпимо будет.
Jenya7
Цитата(AlexRayne @ Jul 20 2018, 18:32) *
все имено так плохо
делайте { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } } - отдельной константой.
код станет чуть менее красивым, но по моему - не сильно ухудшится. терпимо будет.


я хотел чтоб это был единый объект.

отдельно он тоже не принимает как массив структур. только если определяю статический массив.

ну разве что так?
Код
MENU_ITEM subm[]= { {0,"SUBMENU1"}, {1,"SUBMENU2"} , {2,"SUBMENU2"}, {3,"SUBMENU3"} };
MENU menu[5];

menu[0].main_menu.menu_id = 1;
menu[0].main_menu.menu_text = "MENU1";
menu[0].submenu= subm;
jcxz
Цитата(Jenya7 @ Jul 20 2018, 15:25) *
Код
MENU menu[] =
{
    {  { 1, "MENU1"},
       { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } }
    }
};

И на кой на это тратить ОЗУ??? wacko.gif
Arlleex
Цитата(Jenya7 @ Jul 20 2018, 16:25) *
причем если убираю скобки ругается на уровне ошибки.

Как Вы собираетесь объявить массив, содержащий указатель на объект, который еще не объявлен? Вот и весь ответ на вопрос о возможности так схитрить.
Код
typedef struct
{
    uint32_t menu_id;
    char *menu_text;
}MENU_ITEM;

typedef struct
{
    MENU_ITEM main_menu;
    MENU_ITEM *submenu;
}MENU;

int main(void)
{
    MENU_ITEM item[3] = {{0, "SUBMENU1"}, {1, "SUBMENU2"}, {2, "SUBMENU3"}};
    
    MENU menu[] = {{{1, "MENU1"}, &item[0]}, {{1, "MENU1"}, &item[1]}, {{1, "MENU1"}, &item[2]}};
    
    return 0;
}
Jenya7
Цитата(Arlleex @ Jul 20 2018, 20:14) *
Как Вы собираетесь объявить массив, содержащий указатель на объект, который еще не объявлен? Вот и весь ответ на вопрос о возможности так схитрить.
Но инициализируя я же его объявляю. я передаю реальные адреса.

получается промежуточный массив. а что компилятор не достаточно умный чтоб сделать подстановку?
Arlleex
Цитата(Jenya7 @ Jul 20 2018, 18:21) *
Но инициализируя я же его объявляю. я передаю реальные адреса.

Да ну? Где это Вы реальные адреса там передаете, не подскажете?

Цитата(Jenya7 @ Jul 20 2018, 18:21) *
получается промежуточный массив. а что компилятор не достаточно умный чтоб сделать подстановку?

Какой еще промежуточный массив? Компилятор не достаточно умный? Где-то я подобное смелое утверждение слышал уже. И вроде от Вас biggrin.gif
krux
динамика....
в меню....
наибессмысленнейшее решение.

нет, я всё понимаю, если бы у вас был фронтенд-бэкенд с джаваскриптом, node.js и танцовщицами, но нет же, это тупо голый Си!
Serge V Iz
Попробуйте встать на место компилятора. Инициализатор из двух фигурных скобок внутри объемлющей фигурной скобки - это что? Лично я считаю, что это структура, полями которой являются составные типы )

В записи просто недостаточно информации, чтобы вывести тип. Компилятор не сможет корректно такое обработать )
x893
Всё будет во флэш, инициализация не нужна.
Код
typedef struct
{
    const uint32_t menu_id;
    const char *menu_text;
} MENU_ITEM;

typedef struct
{
    const MENU_ITEM main_menu;
    const MENU_ITEM *submenu;
} MENU;

const MENU_ITEM submenu1[] = { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } };
const MENU_ITEM submenu2[] = { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } };
const MENU menu[] =
{
    { { 1, "MENU1"}, submenu1 },
    { { 2, "MENU2"}, submenu2 }
};
Jenya7
Цитата(x893 @ Jul 21 2018, 00:33) *
Всё будет во флэш, инициализация не нужна.
Код
typedef struct
{
     const uint32_t menu_id;
     const char *menu_text;
} MENU_ITEM;

typedef struct
{
     const MENU_ITEM main_menu;
     const MENU_ITEM *submenu;
} MENU;

const MENU_ITEM submenu1[] = { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } };
const MENU_ITEM submenu2[] = { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } };
const MENU menu[] =
{
     { { 1, "MENU1"}, submenu1 },
     { { 2, "MENU2"}, submenu2 }
};

ну а если я записал
Код
{ { 1, "MENU1"},  { {0, "SUBMENU1" }, { 1, "SUBMENU2" }, { 2, "SUBMENU3" } } },

какая разница компилятору. в чем его трудности. это не одно и то же?
x893
Это надо у компилятора спрашивать.
jcxz
Цитата(Jenya7 @ Jul 21 2018, 08:41) *
какая разница компилятору. в чем его трудности. это не одно и то же?

Я думаю у него трудностей нет, только у вас. Так как не он пишет в форум, а вы. biggrin.gif
XVR
Janya7 - вы случайно не состоите в родстве с Гастингсом?

Цитата
— Ну что вы, Пуаро, — пробормотал я. — Мне очень лестно… Вероятно, я так или иначе научился чему-то от вас…
Он отрицательно покачал головой.
— Mais поп, ce n'est pas ca¹. Вы ничему не научились.
— Как? — изумленно спросил я.
— Не удивляйтесь. Все правильно. Никто ни у кого не должен учиться. Каждый человек должен развивать до предела свои возможности, а не копировать кого-то другого. Я не хочу, чтобы вы стали ухудшенным Пуаро. Я хочу, чтобы вы были непревзойденным Гастингсом! Впрочем, вы и есть непревзойденный Гастингс. Вы классически, совершенно нормальны.
GetSmart
Цитата(Jenya7 @ Jul 21 2018, 09:41) *
какая разница компилятору. в чем его трудности. это не одно и то же?

Как откровенничал когда-то (кажется) zltigo: одно дело - стандарт, и немного другое дело - секретные инструкции компиляторописателям.
Жаль, таких зачотных бесед уже давно не наблюдается.

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

Представьте:
Допустим указатель был на структуру1, в которой первым членом идёт структура2. Компилятор, спускаясь/шагая по дереву/структуре опознанного типа, при заполнении содержимого типа <указатель на структуру1> увидев две открывающиеся фигурные скобки без какого-либо подвоха подумает, что вторая скобка есть вход в структуру2. А Jenya7 будет думать, что он первой скобкой создаёт массив структур1, а после второй заполняет первый член структуры1. Можно предположить, что во избежание гемороя/неоднозначностей, первая скобка, при указателе на структуру/юнион трактуется как начало данных этой структуры/юниона. А не гадание на кофейной гуще - захотел ли кодописатель организовать массив и сколько в этом массиве измерений (не элементов!). А может быть ещё и не раз захотел, в подуровнях членов. И полный вынос мозга: массив указателей на массив указателей на массив с типом любых чисел. Компилятор, где-то после 3-ей открытой скобки встретит 0 и не поймёт, что это: нулевой указатель или край иерархии - значение с типом любого числа. Плюс к этому, блок данных (между фигурными скобками) не обязательно заполнять до конца. Можно сразу после нуля поставить закрывающую скобку.

Имхо, самый близкий к желаемому вариант был в 10-ом посте. Грех жаловаться.
XVR
Цитата(Jenya7 @ Jul 21 2018, 08:41) *
какая разница компилятору. в чем его трудности. это не одно и то же?
Нет, это не одно и тоже.
В языке С при инициализации структур и массивов происходит именно ИНИЦИАЛИЗАЦИЯ. Компилятор не может вдруг прервать инициализацию, сделать анонимный массив, что бы инициализировать указатель. Если требуется указатель, то и должен быть передан указатель.
Вопреки распространённому мнению в С указатели и массив НЕ ОДНО И ТОЖЕ! Хотя часто можно использовать идентификатор массива как указатель, наоборот использовать нельзя (указатель вместо массива).

GetSmart
Апосля подумалось. Идея смысла текста топикстартера из первого поста интуитивно понятна (= наиболее проста и очевидна: для указателя агрегатного типа допускать ввод сразу данных агрегатного типа). Только если в стандарте (года?) этот способ не указан, то никаких гарантий, что все компиляторы это будут понимать и делать. Строка не в счёт, она не агрегатный тип.

Пустые скобки при объявлении функции без параметров тоже интуитивно понятны. Хотя некоторым компиляторам очень хочется (приказали?) засунуть туда таракана. А интуитивно непонятно, почему структуры копировать присвоением a=b можно, а массивы (хотя бы с константным размером) - нельзя. И там, и там - агрегатный тип и всё казалось бы корректно, но хрен там. И с приоритетами операций там какая-то алогичность. И что-то ещё было, уже не вспомню.

В си оказывается меняли синтаксис. Существует вариант объявления функций по старому стилю, в котором в скобках только имена, а перед открытием стартового блока функции - объявления этих имён с типами. Любопытно, прототип такой же был или тогда ещё не придумали. Наверное тогда и была та самая декларация независимости функции, из-за которой в новом стиле завели себе таракана. Ещё припоминаю как дизассемблил под досом досовские экзешники и в те времена вызыватель функции сам освобождал стек. Узнавая историю, можно откопать причинно-следственные связи кривизны.
jcxz
Цитата(GetSmart @ Jul 26 2018, 04:22) *
В си оказывается меняли синтаксис. Существует вариант объявления функций по старому стилю, в котором в скобках только имена, а перед открытием стартового блока функции - объявления этих имён с типами.

Ну так это - общеизвестно.
А ещё в конструкторах класса можно члены класса инициализировать до тела функции конструктора с помощью доп. символа ':':
Код
COscWFileDlg::COscWFileDlg(COscDlg *dlg, char const *path, HANDLE h) :
  fname(path), hfile(h), rawNVmax(dlg->rawNVmax), oscRaw(dlg->oscRaw), CDialog(COscWFileDlg::IDD), RThread(NULL)
{
...
}

что я часто и применяю rolleyes.gif
AlexRayne
Цитата(GetSmart @ Jul 26 2018, 04:22) *
А интуитивно непонятно, почему структуры копировать присвоением a=b можно, а массивы (хотя бы с константным размером) - нельзя. И там, и там - агрегатный тип и всё казалось бы корректно, но хрен там. И с приоритетами операций там какая-то алогичность. И что-то ещё было, уже не вспомню.

в с компировать структуры низя, в плюсах можно. думаю в плюсах даже можно скопировать и массив константного размера, лиш бы тип до конца был определен.
но массивы зачастую безразмерные, и в процедурах как правило используется переменная не массива, а указатель на элемент массива. точнее переменная массива используется в качестве указателя на элемент массива. поэтому копирование массива вобчето весьма небезопасно, именно потому что попутать легко - где указатель на корень массива, а где на элемент. со структурами все сильно проще и однозначнее.
aiwa
Цитата(XVR @ Jul 24 2018, 10:49) *
Вопреки распространённому мнению в С указатели и массив НЕ ОДНО И ТОЖЕ! Хотя часто можно использовать идентификатор массива как указатель, наоборот использовать нельзя (указатель вместо массива).

Почему же нельзя?

void fun(int* point)
{
point[3]=4; // использование указателя как массив
}

или, например, заполнить массив можно так:

int array[10];
for(int ind=0;ind<10;ind++)
{
ind[array] = ind;
}
Arlleex
Это все известные вещи.
Но, как было правильно отмечено выше, указатель и имя массива, хотя и являются похожими, являются принципиально разными объектами.
andrew_b
Цитата(AlexRayne @ Jul 26 2018, 12:16) *
в с компировать структуры низя
Да ладно.
Arlleex
Цитата(AlexRayne @ Jul 26 2018, 13:16) *
в с компировать структуры низя...

Можно. Массивы тоже можно, но на основе структур:
Код
struct
{
    int data[100];
}Array1, Array 2;
...
Array1 = Array2;
XVR
Цитата(aiwa @ Jul 26 2018, 12:16) *
Почему же нельзя?

void fun(int* point)
{
point[3]=4; // использование указателя как массив
}
Потому что это не массив, а индексация. И применяется она (СЮРПРИЗ!) к указателям
А массив - это некий объект в памяти, а не набор операций.

aiwa
Цитата(XVR @ Jul 26 2018, 15:32) *
Потому что это не массив, а индексация. И применяется она (СЮРПРИЗ!) к указателям

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

Цитата
6.5.2.1 Array subscripting
Constraints
1
One of the expressions shall have type ‘‘pointer to complete object type ’’, the other expression shall have integer type, and the result has type ‘‘type’’.


Т.е. в "array[index]" array - это ‘‘pointer to complete object type ’’, index - integer type, array[index] - это the result has type ‘‘type’’.

Аналогично с index[array].
XVR
Цитата(aiwa @ Jul 27 2018, 12:09) *
Никакого сюрприза, просто имя массива - является указателем на первый элемент массива.
Не является, а автоматически приводится в нужных случаях. Сравните:

Код
char* pointer;
char array[100];

printf("%d/%d\n", sizeof(pointer), sizeof(array));
Если бы 'имя массива - является указателем на первый элемент массива' то мы получили бы 4/4 (предположим что указатель 4х байтоый). А получим мы 4/100

Честно говоря уже не хочется это разжёвывать - мульён раз об этом писалось, и каждый раз получается портянка на десяток страниц заказчивающаяся каким нибудь холиваром sad.gif
GetSmart
+5 копеек:
индексация указателя не контролирует индекс, а индексация (имени) массива будет, при возможности, проверять индекс на допустимый диапазон.

ЗЫ
Кстати, index[array] какой-то обкуренный товарищ придумал. Любопытно было бы узнать исторические предпосылки или адекватную логическую аргументацию этого кошмара. (а не тупой отсыл к тексту стандарта, в котором не обязана быть аргументация)

Хотелось бы удостовериться, что все интуитивно непонятные места в Си существуют для обхода (старых и новых) граблей или для увеличения концентрации смысла на еденицу текста. Но с минимизацией ущерба общекомпьютерным категориям и терминам, которыми мыслят и на которых общаются разработчики, например, широкого профиля.
Arlleex
Цитата(GetSmart @ Jul 28 2018, 18:36) *
+5 копеек:
индексация указателя не контролирует индекс, а индексация (имени) массива будет, при возможности, проверять индекс на допустимый диапазон.

ЗЫ
Кстати, index[array] какой-то обкуренный товарищ придумал.

Выход да пределы индексации массива может быть проверен только на этапе компиляции, и то не утвердительно всегда.
А фокус с перестановкой имени и индекса следует из того, что перед компиляцией выражение вида a[i] заменяется на *(a + i). Поэтому все логично.
GetSmart
Цитата(Arlleex @ Jul 28 2018, 20:51) *
А фокус с перестановкой имени и индекса следует из того, что перед компиляцией выражение вида a[i] заменяется на *(a + i). Поэтому все логично.

Для начала - спасибо за подсказку. Но не преувеличивайте. То, что кто-то допустим узнал, откуда появился (void) в списке аргументов функции, логичности этому таракану не добавило. Это криво и будет интуитивно непонятно новичкам. А высший пилотаж при разработке языка, в дополнение ко всем достоинствам языка, - когда новичкам без подсказок понятны многие конструкции. Чем меньше им потребуется читать стандарт, хотя бы на начальном этапе, тем качественнее можно оценить работу разработчиков.

Уже теплее и теплее ощущается, что "ТЗ от шефа" было (зачем-то?) в усложнении правил разбора текста компилятору. У массивов, видимо, куча правил перемешалась и вылезла пара грыж.
aiwa
Цитата(GetSmart @ Jul 28 2018, 18:36) *
Кстати, index[array] какой-то обкуренный товарищ придумал. Любопытно было бы узнать исторические предпосылки или адекватную логическую аргументацию этого кошмара. (а не тупой отсыл к тексту стандарта, в котором не обязана быть аргументация)

Не обкуренный товарищ, а группа обкуренных товарищей (WG14). "6.5.2.1 Array subscripting".
Из второго пункта: "The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))."
И далее объяснение - потому что "E1 is an array object (equivalently, a pointer to the initial element of an array object)".

Для примера с sizeof: "6.5.3.4 The sizeof and _Alignof operators", разъясняет, что от sizeof(E1) не стоит ожидать физического размера указателя ибо
sizeof "yields the size of the adjusted (pointer) type".
GetSmart
Цитата(aiwa @ Jul 29 2018, 04:25) *
Из второго пункта: "The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))."

Явно не обозначена аргументация, зачем превращать (классическую) индексацию массива в выражение со сложением. И чем не понравился вариант, когда два (три) оператора (+/-, []) могут быть применимы к массиву. Не обозначены веские причины для того, чтобы массив стал исключением из общих правил нисходящего перемещения по агрегатным типам, когда в тексте левая часть выражения указывает на более массивный агрегатный тип. При этом массивный агр. тип является источником имён и прочей инфы для нисхождения. Для массива это правило интуитивно оптимально при обращениях к многомерным массивам. Здесь же "E1[E2] is identical to (*((E1)+(E2)))" контроль диапазонов многомерия либо невозможен, либо возможен только контроль суммарного размера массива. Плюс, все операторы ".", "->" являются ассиметричными к операндам, аналогично "[]" в большинстве ЯП, изучаемых в образовательных учреждениях. Это правило делает и работу компилятора и читабельность текста проще.

С таким стандартом руки чешутся писать E1[E2]E3[E4] и прочую ерунду. Опять же, ++E1[E2] , где E2 - массив, E1 - integer lvalue, - выносит мозг конкретно. Хочется инкрементнуть элемент массива, но читается по естественным правилам это как увеличение индекса. Плюс: E1++[E2]++. Если ещё покопать, то можно мумию Тутанхамона выкопать.
andrew_b
Цитата(GetSmart @ Jul 29 2018, 08:43) *
Плюс, все операторы ".", "->" являются ассиметричными к операндам, аналогично "[]" в большинстве ЯП, изучаемых в образовательных учреждениях. Это правило делает и работу компилятора и читабельность текста проще.
Когда содавался язык Си, никаких
Цитата
ЯП, изучаемых в образовательных учреждениях
не было.
aiwa
Цитата(GetSmart @ Jul 29 2018, 08:43) *
Явно не обозначена аргументация, зачем превращать (классическую) индексацию массива в выражение со сложением.

Смотря что считать классической моделью. Имхо, в С и есть классическая модель - непосредственное использование индексной адресации машинного кода.

Цитата(GetSmart @ Jul 29 2018, 08:43) *
Здесь же "E1[E2] is identical to (*((E1)+(E2)))" контроль диапазонов многомерия либо невозможен, либо возможен только контроль суммарного размера массива.

По сути "E1[E2] is identical to (*((E1)+(E2)))" - это лишь выражение идеи. Для полной идентичности целое E2 должно быть умножено на типоразмер E1.
Идея состоит в том, что имя массива страдает дуализмом: оно указывает на первый элемент массива но не является указателем в нормативном смысле.
Отсюда естественно вытекает определение многомерных массивов: показывает на элемент, который является массив меньшей размерности.
Поэтому контроль диапазонов вполне возможен и, в принципе, легко реализуем, но, к всеобщему счастью, априори не предусмотрен в С.

Цитата(GetSmart @ Jul 29 2018, 08:43) *
С таким стандартом руки чешутся писать E1[E2]E3[E4] и прочую ерунду. Опять же, ++E1[E2] , где E2 - массив, E1 - integer lvalue, - выносит мозг конкретно. Хочется инкрементнуть элемент массива, но читается по естественным правилам это как увеличение индекса. Плюс: E1++[E2]++. Если ещё покопать, то можно мумию Тутанхамона выкопать.

++E1[E2] - это и есть по естественным правилам инкрементация элемента массива E1[E2].
А вот E1++[E2]++ не сработает. Нужно писать (E1+1)[E2]++;
E1[E2]E3[E4], понятное дело не имеет смысла как и написанные слитно два имени переменных.
GetSmart
Цитата(andrew_b @ Jul 29 2018, 11:14) *
Когда содавался язык Си, никаких {ЯП, изучаемых в образовательных учреждениях} не было.

Да, но тогда переформулируя, в большинстве ЯП высокого уровня того времени.

----------------
Как сказал один мой необкуренный коллега: Что-то у вас тут недоработано ©

Ещё, надеюсь, в стандарте кто-нибудь догадался однозначно указать, что в разделе кода точка с запятой после закрытия непустого блока (}) выражением не считается. (из-за которого предыдущие IF потеряют возможность иметь ELSE)

Upd. И это, разумеется, не касается блока инициализатора. Ещё лучше так: ... указать, что точка с запятой, интерпретируемая первым оператором после закрытия непустого блока кода (закр. фиг. скобки), - выражением не считается.

Отпуск на носу. Отложу раскопки на потом.
andrew_b
Цитата(GetSmart @ Aug 2 2018, 05:41) *
Да, но тогда переформулируя, в большинстве ЯП высокого уровня того времени.
А много ли их тогда было вообще?
Цитата(GetSmart @ Aug 2 2018, 05:41) *
Ещё, надеюсь, в стандарте кто-нибудь догадался однозначно указать, что в разделе кода точка с запятой после закрытия блока (}) выражением не считается. (из-за которого предыдущие IF потеряют возможность иметь ELSE)
А с чего бы? Это пустой оператор. Он тоже подчиняется всем правилам.
GetSmart
Цитата(andrew_b @ Aug 2 2018, 08:51) *
А с чего бы? Это пустой оператор. Он тоже подчиняется всем правилам.

Это удобно для макросов, кои были задуманы сразу же на заре Си. Чтобы не требовалась (ужжасная) обёртка do...while(0).

ps
в пред пост вставил <непустого>, т.к. часто видел и даже сам раньше употреблял {}; в чём-то вроде while (...) {};
andrew_b
При чём тут непустой блок? Пустой оператор -- это ;. Для всех операторов правила общие.
GetSmart
Там немного обновил.

Отвечу так: одной из важнейших целей правил является компактность и ясность программы. Если это требует маленького исключения/особенности, то ничего плохого в этом нет. Которые там и так есть. Это точно менее кошмарно, чем index[array] и мутный do {...} while (0) в макросе. Кроме того, предельная простота совсем не гарантирует однозначности (толкования).


Цитата(aiwa @ Jul 29 2018, 12:38) *
По сути "E1[E2] is identical to (*((E1)+(E2)))" - это лишь выражение идеи. Для полной идентичности целое E2 должно быть умножено на типоразмер E1.
Идея состоит в том, что имя массива страдает дуализмом: оно указывает на первый элемент массива но не является указателем в нормативном смысле.
Отсюда естественно вытекает определение многомерных массивов: показывает на элемент, который является массив меньшей размерности.
Поэтому контроль диапазонов вполне возможен и, в принципе, легко реализуем, но, к всеобщему счастью, априори не предусмотрен в С.

Подскажите тогда, какой тип будут иметь вполне корректные выражения: (при E2=array, E1=index, для одномерного и многомерного массивов)
1: ((E1)+(E2))
2: ((E1)+(E2)+5)
3: ((E1)+5+(E2))
И, если можете, дайте определение/цитату или ссыль на упомянутый термин <типоразмер E1> в тексте <целое E2 должно быть умножено на типоразмер E1>. Это размер элемента ниже по иерархии от имени или размер элемента "на самом дне массива"? Или даже размер целого массива, на который указывает имя? (<типоразмер short> я буквально понимаю как 2 байта {например в Keil for ARMv4..ARMv7}. Типоразмер E5, где E5=структура, я склонен толковать как размер всей структуры, и по этой причине типоразмер E1 (ака массива) - как всего массива целиком. Для версии <имя массива в какой-то мере адрес> считать типоразмером E1 размер адреса - в обсуждаемом контексте вообще маловероятно).
aiwa
Цитата(GetSmart @ Aug 2 2018, 15:04) *
Подскажите тогда, какой тип будут иметь вполне корректные выражения: (при E2=array, E1=index, для одномерного и многомерного массивов)
1: ((E1)+(E2))
2: ((E1)+(E2)+5)
3: ((E1)+5+(E2))


1. указатель на E1-й элемент массива E2.
2. и 3. указатель на (E1+5)-й элемент массива E2.

В случае многомерности E2 элементом будет выступать массив размерности меньшей на единицу, чем E2 .

Когда я говорил про типоразмеры я имел ввиду упомянутые выше ассемблерные команды.
Компилятор С сложение в этих выражениях понимает в смысле арифметики указателей и все получается корректным.



GetSmart
Цитата(aiwa @ Aug 2 2018, 18:00) *
1. указатель на E1-й элемент массива E2.
2. и 3. указатель на (E1+5)-й элемент массива E2.

В случае многомерности E2 элементом будет выступать массив размерности меньшей на единицу, чем E2 .

В стандарте пример подобный описан или какие-то комментарии разработчиков прилагаются?

Мне непонятно, для массива определены особые правила вычисления выражений? По стандартным/общим правилам для варианта 2 будет сперва выполнено (E1)+(E2) и результатом будет (как заявлено в цитате из стандарта) - адрес элемента массива. При многомерном массиве - адрес массива <размерности меньшей на единицу, чем E2>. И уже когда к этому аргументу будет приплюсовываться число 5, то оно, проще говоря, должно быть (наиболее вероятно по вышеобозначенной инфе) индексом следующей (второй) размерности. Однако, если массив одномерный, то добавление числа к адресу, указывающему не на массив, истолкуется как добавление числа к указателю такого типа. И результат для одномерного массива будет действительно похож на <2. и 3. указатель на (E1+5)-й элемент массива E2.>
aiwa
Цитата(GetSmart @ Aug 2 2018, 17:17) *
Мне непонятно, для массива определены особые правила вычисления выражений? По стандартным/общим правилам для варианта 2 будет сперва выполнено (E1)+(E2) и ....


Так все это E2+E1 и подобные выражения не являются исходным для применения правил, они лишь объясняют использование "array subscripting".

Грубо говоря, они помогают понимать как компилятор должен обходиться с выражениями вида expr1[expr2] и подобными.

Если E2 - многомерный массив, например E2[10][20][30][40][50]
2. и 3. варианты подходят к случаю E2[E1+5], результатом которого будет (E1+5)-й подмассив типа ()[20][30][40][50];
Для E2[E1][5] выражение будет композицией вышеупомянутого правила: сначала получается из "E2[E1]" (E1)-й подмассив типа ()[20][30][40][50] - грубо говоря к адресу E2 прибавляется E1*типоразмер ()[20][30][40][50], и затем к полученному результату правило применяют повторно для [5] - здесь уже арифметика указателей должна прибавлять пять типоразмеров меньшей размерности ()[30][40][50].

Под типразмером я имею ввиду физический размер с учетом выравнивания.

В стандарте, наверное, нет никаких типоразмеров, он оперирует "элементами массива", вводя многомерность по рекурсии.






GetSmart
Цитата(aiwa @ Aug 2 2018, 18:50) *
Так все это E2+E1 и подобные выражения не являются исходным для применения правил, они лишь объясняют использование "array subscripting".

Грубо говоря, они помогают понимать как компилятор должен обходиться с выражениями вида expr1[expr2] и подобными.

В вышеобсуждаемой цитата из стандарта явно указано, что такое выражение разрешено стандартом (сложение чисел с именем массива). При неуказании особых правил этого "изврата" применяются стандартные правила приоритетов и ассоциативности. Без оговорок и комментариев на уровне стандарта иначе это нельзя истолковать.


Лучше даже уточнить:
Цитата
По стандартным/общим правилам для варианта 2 будет сперва выполнено (E1)+(E2) и результатом будет (как заявлено в цитате из стандарта) - адрес элемента массива. При многомерном массиве - адрес массива <размерности меньшей на единицу, чем E2>. И уже когда к этому аргументу будет приплюсовываться число 5, то оно, проще говоря, должно быть (наиболее вероятно по вышеобозначенной инфе) индексом следующей (второй) размерности. Однако, если массив одномерный, то добавление числа к адресу, указывающему не на массив, истолкуется как добавление числа к указателю такого типа.

<Адрес> точнее будет заменить на <что-то> (неуказанное в стандарте), содержащее адрес, указывающий на вышеобозначенный тип. (пример: <сперва выполнено (E1)+(E2) и результатом будет {как заявлено в цитате из стандарта} - адрес элемента массива.> ==> <что-то> с адресом элемента массива) И к этому <что-то> применим оператор *. К указателю он тоже применим, но их идентичность это не доказывает, без документального подтверждения.

Свой пред пост дополнил.
aiwa
Цитата(GetSmart @ Aug 2 2018, 18:00) *
В вышеобсуждаемой цитата из стандарта явно указано, что такое выражение разрешено стандартом (сложение чисел с именем массива).


Если уж быть корректным, то сложение чисел не с именем массива, а с указателем (на тип элементов из которых состоит массив), в качестве которого выступает имя массива и равным алресу его "инициирующего элемента".




Цитата(GetSmart @ Aug 2 2018, 18:00) *
<Адрес> точнее будет заменить на <что-то> (неуказанное в стандарте), содержащее адрес, указывающий на вышеобозначенный тип. (пример: <сперва выполнено (E1)+(E2) и результатом будет {как заявлено в цитате из стандарта} - адрес элемента массива.> ==> <что-то> с адресом элемента массива) И к этому <что-то> применим оператор *.


В стандарте в качестве этого <что-то> употребляют термин "роinter". Это к тому, из-за чего весь сыр-бор пошел.
GetSmart
Цитата(aiwa @ Aug 2 2018, 19:53) *
В стандарте в качестве этого <что-то> употребляют термин "роinter". Это к тому, из-за чего весь сыр-бор пошел.

Туда же добавил
<К указателю он тоже применим, но их идентичность это не доказывает, без документального подтверждения.>

Цитата(aiwa)
Если уж быть корректным, то сложение чисел не с именем массива, а с указателем (на тип элементов из которых состоит массив), в качестве которого выступает имя массива и равным алресу его "инициирующего элемента".


Сложение с именем массива:
result = *(array+5)

Сложение с указателем (на тип элементов из которых состоит массив):
result = *(&array[0]+5)

В цитате было (буквально) сложение с именем массива.

Цитата
The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

Переводится как <Определением <subscript operator []> является то, что {неявно подразумевается: выражение} E1[E2] идентично {выражению} (*((E1)+(E2)))>
Цитата
И далее объяснение - потому что "E1 is an array object (equivalently, a pointer to the initial element of an array object)".

Из чего следует, что в текстах разрешено использовать выражения со сложениями целых чисел с именами массивов. Без оговорок на размерность массивов.

Upd: А ещё точнее: с такими же ограничениями как и для оператора [].
Всё это не исключает при сложениях и такой возможности: при невозможности к аргументу применить оператор [], могут быть применены другие правила (если они определены), как то: трансформация аргумента в указатель и сложение с этим указателем.

То, что в определении имя заключено в круглые скобки - сути не меняет, т.к. в этом выражении они являются оператором изменения очерёдности выполнения других операторов. (чорт его знает как скобки там дословно определили) И (array)[index] по смыслу исполнения равноценно array[index], когда внутри скобок нет операторов. {неявно подразумевая: в тексте после препроцессора}

-------------
Дежа-вю
Цитата(Сергей Борщ)
От перемены мест слагаемых сумма не меняется.

Цитата
Не надо гипотез. В стандарте все описано. И неявные преобразования, и коммуникативность сложения.
andrew_b
Цитата(GetSmart @ Aug 2 2018, 19:49) *
Туда же добавил
Вы это прекращайте. С постоянными правками предыдущих сообщений трудно следить за дискуссией.
Цитата
<К указателю он тоже применим, но их идентичность это не доказывает, без документального подтверждения.>
Почему бы вам самим взять и не почитать стандарт языка Си? hint: google://ansi_c.pdf
GetSmart
Я пару раз добавил в конец предыдущих постов одно и два предложения. И один раз абзац с отметкой Upd. В последний раз даже не видел, что уже новый пост появился. Редактирование постов для уточнения мыслей и существует. Ничего криминального в этом нет.

Не удержался. Третий раз дополнил предыдущий пост.

Позже почитаю, после отпуска.
aiwa
Цитата(GetSmart @ Aug 2 2018, 19:49) *
Сложение с именем массива:
result = *(array+5)

Сложение с указателем (на тип элементов из которых состоит массив):
result = *(&array[0]+5)

В цитате было (буквально) сложение с именем массива.


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

Приведенные Вами два примера отличаются лишь небольшой деталью.
Во втором Вы сами используете указатель, а в первом тот же указатель получается "implicitly" - согласно стандарту: "by converting an array name to a pointer".


Цитата(GetSmart @ Aug 2 2018, 19:49) *
Из чего следует, что в текстах разрешено использовать выражения со сложениями целых чисел с именами массивов. Без оговорок на размерность массивов.


Ну да, про коммутативность это понятно - побочный эффект.
Равно как по той же причине в массиве размерности 5x5 доступ к "последнему" элементу a[4][4] вполне может быть реализован как a[15][0] или a[0][15].

GetSmart
Цитата(aiwa @ Aug 3 2018, 13:32) *
Не путайте терминологию: имя массива - это идентификатор, арифметические с которыми бессмыслены.

Приведенные Вами два примера отличаются лишь небольшой деталью.
Во втором Вы сами используете указатель, а в первом тот же указатель получается "implicitly" - согласно стандарту: "by converting an array name to a pointer".

Определение дано на текстовом примере. После этого запрещать описание словами текстовых конструкций языка бессмысленно. Кроме того, в данном контексте <имя массива> более однозначно описывает <инструкцию> писателя кода. Если я напишу <массив>, то сразу подменю обсуждаемую <инструкцию> до многих вариантов текстового представления. Поэтому такие формулировки имеют право быть. Добавлять везде <в тексте> излишне, это неявно контекстно подразумевается. Скорее будет важно: до препроцессора или после, всякие области видимости, наложения имён переменных, макросов и прочего. По-умолчанию в таких формулировках разумно считать, что интерпретация текста по стандарту в том тексте выявит однозначно: имя массива, оператор сложения и целое число 5. И оператор сложения будет выполнен до всех иных операторов.

Цитата(aiwa @ Aug 3 2018, 13:32) *
Равно как по той же причине в массиве размерности 5x5 доступ к "последнему" элементу a[4][4] вполне может быть реализован как a[15][0] или a[0][15].

Ерунда какая-то. 5*5=25
aiwa
Цитата(GetSmart @ Aug 3 2018, 15:09) *
...Если я напишу <массив>, то сразу подменю обсуждаемую <инструкцию> до многих вариантов текстового представления. Поэтому такие формулировки имеют право быть.

В оригинале сказано именно массив, что эквивалентно указателю на первый элемент: "if E1 is an array object (equivalently, a pointer to the initial element of an array object)"
Но если массив или имя массива смотрятся как синонимы, то "прибавление к имени массива" как-то не комильфо.

Цитата(GetSmart @ Aug 3 2018, 15:09) *
Ерунда какая-то. 5*5=25

Ну да, отвлекся и написал для массива 4x4, правильно было бы а[0][24] и a[24][0]. Но не важно, - главное, что коммутативность арифметики с указателем приводит к такому побочному эффекту.
Поэтому не стоит это ставить во главу угла.
GetSmart
Цитата(aiwa @ Aug 3 2018, 16:57) *
В оригинале сказано именно массив, что эквивалентно указателю на первый элемент: "if E1 is an array object (equivalently, a pointer to the initial element of an array object)"

<(equivalently, a pointer> в данном контексте переводится как: <(равно{значно} {допустимо}, если это указатель>
фигурными скобками выделил неявный смысл, который, при желании, можно не писать. В контексте этого абзаца <equivalently> не определяет, что везде в языке оба варианта равнозначны. Ещё, из этой цитаты не понять, какое действие вызывает оператор [], применимый к обычному указателю. Даже из всей главы <6.5.2.1 Array subscripting> непонятно, какое действие по стандарту выполняет применение [] к указателю на не массив (на не элемент массива). В её вступлении написали
Цитата
One of the expressions shall have type "pointer to
object type", the other expression shall have integer type,
and the result has type "type"

Далее везде "если это массив или указатель на начальный элемент массива то ...".
PS но я мельком прочитал эти три абзаца. Прошу опровергнуть, если я неправ.

Upd
Учитывая вступительную цитату, с которой я только что ознакомился моё утверждение <В цитате было (буквально) сложение с именем массива. >
правильнее заменить на <В цитате вполне допускалось сложение с именем массива.>
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2024 Invision Power Services, Inc.