|
|
  |
Определение размера массива на этапе компиляции, Задачка |
|
|
|
Sep 10 2012, 15:54
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (_Pasha @ Sep 10 2012, 20:41)  Ответ лежит в личке. Посмотрел, спасибо. Насколько понял, это несколько не то - эта штука чекает размер с целью контроля переполнения памяти. Но она никак не поможет узнать размер массива внутри функции, которая видит указатель. Ну, и весьма частное решение, даже если бы делало то, что надо. QUOTE (Xenia @ Sep 10 2012, 22:29)  Всё это - палиативные решения. Окажется массив двухмерным - опять возникнут проблемы пуще прежних. Двумерных массивов в С/С++ не бывает. QUOTE (Xenia @ Sep 10 2012, 22:29)  Если решать проблему, то на корню. Создавать класс, в которую входит указатель на массив Не нужно придумывать условия задачи. Они уже определены и вполне однозначны и просты. И решение есть, простое и эффективное. QUOTE (kurtis @ Sep 10 2012, 22:36)  Так какой правильный ответ? Давайте ещё немножко подождём, до завтра, до середины дня, пусть хотя бы сутки будут на решение.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Sep 10 2012, 16:12
|
Местный
  
Группа: Участник
Сообщений: 421
Регистрация: 2-01-08
Пользователь №: 33 778

|
С макросами я бы делал как-то вот так. Код #define AR(a) (struct ar __a = {(void *) (a), sizeof(a)}, __a)
struct ar { void *p; int sz; };
#define FOO(a) foo(AR(a))
void foo(struct ar a);
...
int A[] = {1, 2, 3};
FOO(A); Точнее я бы так не делал  Обычно можно проще, но для этого надо видеть всю задачу, в такой постановке ничего не поделать.
Сообщение отредактировал amaora - Sep 10 2012, 16:16
|
|
|
|
|
Sep 10 2012, 17:02
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
QUOTE Двумерных массивов в С/С++ не бывает. Шутить изволите? CODE int A[5][6];
int main() { A[2][3]=123; A[4][2]=456; A[2][4]=789; ... CODE 24 int A[5][6]; \ A: \ 00000000 DS8 120 ... \ 00000004 .... LDR.N R0,??DataTable0 \ 00000006 7B21 MOVS R1,#+123 \ 00000008 C163 STR R1,[R0, #+60] 29 A[4][2]=456; \ 0000000A 4FF4E471 MOV R1,#+456 \ 0000000E 8166 STR R1,[R0, #+104] 30 A[2][4]=789; \ 00000010 40F21531 MOVW R1,#+789 \ 00000014 0164 STR R1,[R0, #+64] ... \ ??DataTable0: \ 00000000 ........ DC32 A
Хотя, я конечно понимаю, что суть двумерного массива всего лишь массив массивов
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Sep 11 2012, 00:59
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (Rst7 @ Sep 11 2012, 00:02)  Шутить изволите? Ничуть. QUOTE (Rst7 @ Sep 11 2012, 00:02)  CODE int A[5][6];
int main() { A[2][3]=123; A[4][2]=456; A[2][4]=789; ... [...] Хотя, я конечно понимаю, что суть двумерного массива всего лишь массив массивов  Именно. А массив массивов - это ни разу не двумерный массив. sizeof элемента массива всегда один и тот же по определению (т.к. массив - агрегатный объект, состоящий из элементов одного типа). Для настоящего (тру Ъ) двумерного массива нотация A[0] не имеет смысла, т.к. не индексирует элемент, а в С/С++ вполне имеет, но возвращает указатель на массив (точнее, указатель на указатель). Помнится, на фидоэхе su.с-сpp один очень квалифицированный человек весьма наглядно и на примерах показал ключевую разницу между этими вещами и к чему приводит неверная трактовка. Впрочем, соглашусь с тем, что сам по себе термин "двумерный массив" в C/C++ вполне имеет право быть, только нужно всегда иметь в виду контекст применения этого термина. QUOTE (Xenia @ Sep 11 2012, 01:31)  Еще бы темплейты задействовать  Это мысль в правильном направлении. QUOTE (_Pasha @ Sep 11 2012, 01:35)  По идее, она возвращает размер, тип возврата - size_t. Вроде всё ОК. А дальше по Жванецкому: включаем - не работает.  Странно. Она-то возвращает, но ей надо видеть определение объекта в точке вызова. Если это сделать при вызове функции - при передаче аргументов, то оно сработает, но ровно так же работает и sizeof(), с этим нет проблем. А вот внутри функции аргумент вырождается в указатель - что оно тут сможет извлечь?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Sep 11 2012, 03:35
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
QUOTE Для настоящего (тру Ъ) двумерного массива нотация A[0] не имеет смысла, т.к. не индексирует элемент, а в С/С++ вполне имеет, но возвращает указатель на массив (точнее, указатель на указатель). Ну, во-первых, не указатель на указатель, а указатель на элемент. Непонятно только, чему это противоречит. Хотите получить sizeof элемента - так и берите элемент - a[i][j]. sizeof(а[0]) тоже имеет вполне логичное значение, равное размеру строки в массиве. Все четко и логично.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Sep 11 2012, 04:37
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (Rst7 @ Sep 11 2012, 10:35)  Ну, во-первых, не указатель на указатель, а указатель на элемент. Непонятно только, чему это противоречит.
Хотите получить sizeof элемента - так и берите элемент - a[i][j].
sizeof(а[0]) тоже имеет вполне логичное значение, равное размеру строки в массиве.
Все четко и логично. Будь это настоящим двумерным массивом, операция a + 1 давала бы адрес следующего элемента, а в нашем случае это будет адрес следующего массива. Разница существенная. Повторять всё обилие различий не хочется, тут подробнее.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Sep 11 2012, 05:04
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
QUOTE Повторять всё обилие различий не хочется, тут подробнее. Бред там написан. QUOTE Будь А полноценным двумерным массивом - т.е. законченным, целостным объектом, то выражение: А + 1 означало бы адрес следующего такого двумерного массива, Например, int A[10]; и последующее выражение A+1 указывает не на A[10], а на A[1], так почему там требуют другого поведения, соответствующему, кстати, указателю на двумерный массив?
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Sep 11 2012, 05:31
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (Rst7 @ Sep 11 2012, 12:04)  Например, int A[10]; и последующее выражение A+1 указывает не на A[10], а на A[1], так почему там требуют другого поведения, соответствующему, кстати, указателю на двумерный массив? Допустим, у нас есть настоящий честный двумерный массив А[10][20]. Что возвращает A + 1? И что возвращает это выражение в случае сишного массива?
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Sep 11 2012, 07:47
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
QUOTE Допустим, у нас есть настоящий честный двумерный массив А[10][20]. Что возвращает A + 1? Приведите пример языка с "настоящим честным двумерным массивом", в котором допустима операция A+1. Еще раз, Ваше утверждение (и утверждение по ссылке, которую Вы дали) требует поведения при операции A+1 такого, какое в Си записывается следующим образом: CODE int (*a)[5][6];
(*a)[1][2]=123; //Запись значения в первый двумерный массив (*(a+1))[1][2]=345; //Запись значения во второй массив Несмотря на то, что в 99% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Sep 11 2012, 08:31
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
QUOTE (Rst7 @ Sep 11 2012, 14:47)  Приведите пример языка с "настоящим честным двумерным массивом", в котором допустима операция A+1. Например, язык пакета Matlab. Или какой-нибудь другой высокоуровневый язык (тот же питон с библиотекой numpy). В низкоуровенвых языках, как С/C++, паскаль и подобных, представление соответствует уровню, т.е. является тоже низкоуровневым - непрерывная область памяти с элементами одного и того же типа. Максимум что они позволяют - массивы массивов. Тем не менее концепция двумерного массива никуда не девается. В мире полно объектов, которые описываются именно двумерным массивом, а не массивом массивов. Попытка адресоваться по одной координате всегда приводит к декомпозиции исходного типа и он перестаёт существовать. Например, есть объект - точка на экране. Она характеризуется двумя координатами. И изображение на экране - это двумерный массив этих точек. Попытка обращаться только через одну координату автоматически переводит адресуемый элемент из точки в строку или столбец. Нормальное представление двумерного массива вполне допускает обращение к его фрагментам - строкам, столбцам и просто прямоугольным фрагментам, и предоставляет для этого соответствующие средства (slice). Вы показывали, как ловко на С получить строку из "двумерного" массива. Покажите, как получить столбец? Или прямоугольный фрагмент? QUOTE (Rst7 @ Sep 11 2012, 14:47)  Еще раз, Ваше утверждение (и утверждение по ссылке, которую Вы дали) требует поведения при операции A+1 такого, какое в Си записывается следующим образом: CODE int (*a)[5][6];
(*a)[1][2]=123; //Запись значения в первый двумерный массив (*(a+1))[1][2]=345; //Запись значения во второй массив Настоящий двумерный массив в принципе не поддерживает такую нотацию обращения - через разыменовывание. QUOTE (Rst7 @ Sep 11 2012, 14:47)  Несмотря на то, что в 99% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу. Самая эта тема сутью задачи подчёркивает эту разницу.  Собственно, возвращаемся к точке начала спора. Спор о терминах. Понимание сути у всех есть. Двумерных массивов в С/C++ нет. Есть массивы массивов. Разница между ними есть. В ряде случаев массив массивов может использоваться в качестве двумерного массива с некоторыми ограничениями. Учитывая этот контекст, вполне допустимо употреблять термин "двумерный массив" для краткости (и лучше оговаривать сразу, что имеется в виду), но всегда помнить, что за этим стоит. На этом предлагают дискуссию закончить, дабы не тратить время и ходить по кругу.
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
Sep 11 2012, 10:09
|

Adept
     
Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343

|
Наверное, пришло время обнародовать решение, как вчера было обещано. Решение на самом деле очень простое и эффективное. Выглядит так: CODE template <typename T, size_t N> void f(T (&a)[N]) { ... // используем N - это длина массива } В общем случае это не тот размер, который возвращает sizeof(), а именно длина массива, но именно она-то и нужна. А размер получается тоже элементарно - N*sizeof(T). Всё на этапе компиляции. Возможно, не всем понятно, как это работает, поэтому краткое пояснение. В С++ инстанцирование функции по шаблону может быть явным, когда задаются параметры шаблона, и неявным, когда компилятор сам исходя из контекста использования, может сгенерировать реализацию. Именно вот такое неявное инстанцирование тут и используется. При этом вся информация у компилятора есть - есть объект-массив, про который всё известно - и тип элементов, и длина массива. Далее, ключевой момент: аргументом функции заявлена ссылка на массив, состоящий из элементов типа T и длиной N. Теперь в точке вызова: CODE int A[] = { 1, 2, 3, 4 }; ...
f(A); компилятор находит использование функции f(), ищет её реализацию, находит шаблон, анализирует контекст (а по контексту требуется именно массив - ссылка на него, а не указатель) и генерирует функцию f(int &а[4]). Всё, дело сделано. Поскольку параметры шаблона доступны внутри определения функции, то доступен и тип, и длина массива. Все действия производятся на этапе компиляции, т.е. получение длины массива достигается без единой инструкции, выполняемой на рантайме. Пример: CODE template <typename T, int N> int len(T (& a)[N]) { return N; }
const int a[] = {1,1,1,1,2,3,4,5,6}; // 9 элементов const int b[] = {1,1,1,5,6}; // 5 элементов
volatile int d;
void main() { d = len(a); d = len(b);
} Результат (MSP430/IAR): CODE d = len(a); 000000 B2400900.... MOV.W #0x9, &d d = len(b); 000006 B2400500.... MOV.W #0x5, &d
--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|