реклама на сайте
подробности

 
 
4 страниц V  < 1 2 3 4 >  
Reply to this topicStart new topic
> Определение размера массива на этапе компиляции, Задачка
kurtis
сообщение Sep 10 2012, 15:36
Сообщение #16


Местный
***

Группа: Свой
Сообщений: 466
Регистрация: 21-06-05
Пользователь №: 6 205



Так какой правильный ответ?
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 10 2012, 15:54
Сообщение #17


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) *
Так какой правильный ответ?

Давайте ещё немножко подождём, до завтра, до середины дня, пусть хотя бы сутки будут на решение.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
amaora
сообщение Sep 10 2012, 16:12
Сообщение #18


Местный
***

Группа: Участник
Сообщений: 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);


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

Сообщение отредактировал amaora - Sep 10 2012, 16:16
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 10 2012, 17:02
Сообщение #19


Йа моск ;)
******

Группа: Модераторы
Сообщений: 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


Хотя, я конечно понимаю, что суть двумерного массива всего лишь массив массивов wink.gif


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
ViKo
сообщение Sep 10 2012, 18:16
Сообщение #20


Универсальный солдатик
******

Группа: Модераторы
Сообщений: 8 634
Регистрация: 1-11-05
Из: Минск
Пользователь №: 10 362



Я бы пользовался макроподстановкой, описанной в первом сообщении
Но, если не нравится так, можно заменить саму функцию
Код
#define a_s(array) arr_sum(array, sizeof(array)/sizeof(array[0]))

uint32_t arr_sum(uint32_t *p, uint32_t s);
...
Go to the top of the page
 
+Quote Post
Xenia
сообщение Sep 10 2012, 18:31
Сообщение #21


Гуру
******

Группа: Модератор FTP
Сообщений: 4 479
Регистрация: 20-02-08
Из: Москва
Пользователь №: 35 237



Еще бы темплейты задействовать sm.gif
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Sep 10 2012, 18:35
Сообщение #22


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(dxp @ Sep 10 2012, 18:54) *
Насколько понял, это несколько не то - эта штука чекает размер с целью контроля переполнения памяти.

По идее, она возвращает размер, тип возврата - size_t. Вроде всё ОК. А дальше по Жванецкому: включаем - не работает. sad.gif Странно.
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 11 2012, 00:59
Сообщение #23


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;
...


[...]
Хотя, я конечно понимаю, что суть двумерного массива всего лишь массив массивов wink.gif

Именно. А массив массивов - это ни разу не двумерный массив. sizeof элемента массива всегда один и тот же по определению (т.к. массив - агрегатный объект, состоящий из элементов одного типа). Для настоящего (тру Ъ) двумерного массива нотация A[0] не имеет смысла, т.к. не индексирует элемент, а в С/С++ вполне имеет, но возвращает указатель на массив (точнее, указатель на указатель). Помнится, на фидоэхе su.с-сpp один очень квалифицированный человек весьма наглядно и на примерах показал ключевую разницу между этими вещами и к чему приводит неверная трактовка. Впрочем, соглашусь с тем, что сам по себе термин "двумерный массив" в C/C++ вполне имеет право быть, только нужно всегда иметь в виду контекст применения этого термина.

QUOTE (Xenia @ Sep 11 2012, 01:31) *
Еще бы темплейты задействовать sm.gif

Это мысль в правильном направлении.

QUOTE (_Pasha @ Sep 11 2012, 01:35) *
По идее, она возвращает размер, тип возврата - size_t. Вроде всё ОК. А дальше по Жванецкому: включаем - не работает. sad.gif Странно.

Она-то возвращает, но ей надо видеть определение объекта в точке вызова. Если это сделать при вызове функции - при передаче аргументов, то оно сработает, но ровно так же работает и sizeof(), с этим нет проблем. А вот внутри функции аргумент вырождается в указатель - что оно тут сможет извлечь?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 11 2012, 03:35
Сообщение #24


Йа моск ;)
******

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



QUOTE
Для настоящего (тру Ъ) двумерного массива нотация A[0] не имеет смысла, т.к. не индексирует элемент, а в С/С++ вполне имеет, но возвращает указатель на массив (точнее, указатель на указатель).


Ну, во-первых, не указатель на указатель, а указатель на элемент. Непонятно только, чему это противоречит.

Хотите получить sizeof элемента - так и берите элемент - a[i][j].

sizeof(а[0]) тоже имеет вполне логичное значение, равное размеру строки в массиве.

Все четко и логично.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 11 2012, 04:37
Сообщение #25


Adept
******

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



QUOTE (Rst7 @ Sep 11 2012, 10:35) *
Ну, во-первых, не указатель на указатель, а указатель на элемент. Непонятно только, чему это противоречит.

Хотите получить sizeof элемента - так и берите элемент - a[i][j].

sizeof(а[0]) тоже имеет вполне логичное значение, равное размеру строки в массиве.

Все четко и логично.

Будь это настоящим двумерным массивом, операция a + 1 давала бы адрес следующего элемента, а в нашем случае это будет адрес следующего массива. Разница существенная. Повторять всё обилие различий не хочется, тут подробнее.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 11 2012, 05:04
Сообщение #26


Йа моск ;)
******

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



QUOTE
Повторять всё обилие различий не хочется, тут подробнее.


Бред там написан.
QUOTE
Будь А полноценным двумерным массивом - т.е. законченным, целостным
объектом, то выражение:
А + 1
означало бы адрес следующего такого двумерного массива,


Например, int A[10]; и последующее выражение A+1 указывает не на A[10], а на A[1], так почему там требуют другого поведения, соответствующему, кстати, указателю на двумерный массив?


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 11 2012, 05:31
Сообщение #27


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? И что возвращает это выражение в случае сишного массива?


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Rst7
сообщение Sep 11 2012, 07:47
Сообщение #28


Йа моск ;)
******

Группа: Модераторы
Сообщений: 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% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 11 2012, 08:31
Сообщение #29


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% случаев утверждают, что в Си массивы и указатели есть одно и тоже, на самом деле между ними есть четкая разница. Непонимание порождает путаницу.

Самая эта тема сутью задачи подчёркивает эту разницу. sm.gif

Собственно, возвращаемся к точке начала спора. Спор о терминах. Понимание сути у всех есть. Двумерных массивов в С/C++ нет. Есть массивы массивов. Разница между ними есть. В ряде случаев массив массивов может использоваться в качестве двумерного массива с некоторыми ограничениями. Учитывая этот контекст, вполне допустимо употреблять термин "двумерный массив" для краткости (и лучше оговаривать сразу, что имеется в виду), но всегда помнить, что за этим стоит. На этом предлагают дискуссию закончить, дабы не тратить время и ходить по кругу.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
dxp
сообщение Sep 11 2012, 10:09
Сообщение #30


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


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post

4 страниц V  < 1 2 3 4 >
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 7th July 2025 - 19:04
Рейтинг@Mail.ru


Страница сгенерированна за 0.01531 секунд с 7
ELECTRONIX ©2004-2016