Вопросы по С/С++ (СИ)
А. дошло. никак не мог додуматься зачем нужно имя при определении типа. Теперь понял.
- Реклама
- Сообщения: 60
- Зарегистрирован: Вс ноя 13, 2022 14:58:17
[uquote="uldemir",url="/forum/viewtopic.php?p=4394254#p4394254"]Как переключать контекст я и так знаю - там проблема в цикличной зависимости определений друг от друга. Которая не проблема для, говорят, C++, но чистый C такого не позволяет. А про связный список я не настаивал, но мне его предложили и хочу знать.
...как написать связный список на си? Чтобы линки создались уже на этапе компиляции. И чтобы не выдумывать каждой записи уникальное имя. Или как в этом кадре из видео,

не нужно было в случае, если захочу вставить команду между "s" и "g" переправлять в каждой строчке &LL[3] на &LL[4], затем &LL[4] на &LL[5] и так далее до 85-го элемента массива.
И еще, чтобы длина строки содержащей команду не была константной. но typedef, кажется, такое не приемлет.[/uquote]
Пример вы привели, мягко сказать, неудачный. Для начала нужно понять что собой представляют массивы и списки, и для чего они могут быть использованы.
Прежде всего, с точки зрения использования памяти, массивы являются статическими объектами. Т.е требуемый объём памяти определяется на этапе компиляции. Допустим, вы хотите сделать словарь на определённо количество слов и оформили его в виде массива. В этом случае вы не сможете в процессе работы программы увеличить количество слов в словаре, если это потребуется. Можно конечно на этапе компиляции сделать размер массива больше, чем требуется изначально. Скажем на момент компиляции в словаре имеется 10 слов, но вы сделаете массив на 100 слов, в расчёте на то, что в процессе работы программы словарь может быть увеличен. Но при этом могут возникнуть две проблемы. Во-первых нет гарантии, что этого массива может хватить (скажем, вы предполагали увеличение словаря до 100, а понадобилось 101 слово). Во-вторых, память будет использоваться не рационально, если количество слов в словаре будет меньше, чем вы расчитывали.
Теперь о списках. В противоположность массивам, списки являются динамическими объектами. Изначально список может вообще быть пустым и никакой памяти выделять не потребуется. Элементы списка создаются и добавляются к списку во время работы программы. Но ту возникает вопрос: а где взять необходимую память? Ответ - память берется из так называемой "кучи", которая обычно имеется в системе. Для этой цели в библиотеки Си имеются соответствующие функции, например malloc (выделить память) и free (освободить память). Но при этом для работы со списками потребуются дополнительные программы.
Наиболее часто связные списки используются в различных трансляторах, когда количество символов в транслируемой программе заранее неизвестно.
Теперь об инициализации списков. В приведённом вам примере список вообще не нужен, ибо все элементы статические. Здесь лучше использовать обыкновенный массив. И памяти меньше потребуется, и работать с массивом будет проще. Что же касается инициализации самих списков на этапе компиляции не необходимости указывать адрес следующего элемента в списке, поскольку этот адрес будет определяться в процессе создания списка при работе программы. Ниже приводится фрагмент программы инициализации списка. На этапе компиляции определяются только те элементы списка, которые должны быть в списке изначально.
Функция add_sym как раз используется для добавления к списку. При этом последовательность добавления элементов в список может быть произвольной.
...как написать связный список на си? Чтобы линки создались уже на этапе компиляции. И чтобы не выдумывать каждой записи уникальное имя. Или как в этом кадре из видео,
не нужно было в случае, если захочу вставить команду между "s" и "g" переправлять в каждой строчке &LL[3] на &LL[4], затем &LL[4] на &LL[5] и так далее до 85-го элемента массива.
И еще, чтобы длина строки содержащей команду не была константной. но typedef, кажется, такое не приемлет.[/uquote]
Пример вы привели, мягко сказать, неудачный. Для начала нужно понять что собой представляют массивы и списки, и для чего они могут быть использованы.
Прежде всего, с точки зрения использования памяти, массивы являются статическими объектами. Т.е требуемый объём памяти определяется на этапе компиляции. Допустим, вы хотите сделать словарь на определённо количество слов и оформили его в виде массива. В этом случае вы не сможете в процессе работы программы увеличить количество слов в словаре, если это потребуется. Можно конечно на этапе компиляции сделать размер массива больше, чем требуется изначально. Скажем на момент компиляции в словаре имеется 10 слов, но вы сделаете массив на 100 слов, в расчёте на то, что в процессе работы программы словарь может быть увеличен. Но при этом могут возникнуть две проблемы. Во-первых нет гарантии, что этого массива может хватить (скажем, вы предполагали увеличение словаря до 100, а понадобилось 101 слово). Во-вторых, память будет использоваться не рационально, если количество слов в словаре будет меньше, чем вы расчитывали.
Теперь о списках. В противоположность массивам, списки являются динамическими объектами. Изначально список может вообще быть пустым и никакой памяти выделять не потребуется. Элементы списка создаются и добавляются к списку во время работы программы. Но ту возникает вопрос: а где взять необходимую память? Ответ - память берется из так называемой "кучи", которая обычно имеется в системе. Для этой цели в библиотеки Си имеются соответствующие функции, например malloc (выделить память) и free (освободить память). Но при этом для работы со списками потребуются дополнительные программы.
Наиболее часто связные списки используются в различных трансляторах, когда количество символов в транслируемой программе заранее неизвестно.
Теперь об инициализации списков. В приведённом вам примере список вообще не нужен, ибо все элементы статические. Здесь лучше использовать обыкновенный массив. И памяти меньше потребуется, и работать с массивом будет проще. Что же касается инициализации самих списков на этапе компиляции не необходимости указывать адрес следующего элемента в списке, поскольку этот адрес будет определяться в процессе создания списка при работе программы. Ниже приводится фрагмент программы инициализации списка. На этапе компиляции определяются только те элементы списка, которые должны быть в списке изначально.
Код: Выделить всё
add_sym("ADC", I_ADC, OC_LD, &instruction_section, &system_st);
add_sym("ADD", I_ADD, OC_LD, &instruction_section, &system_st);
add_sym("ASL", I_ASL, OC_1GEN, &instruction_section, &system_st);
add_sym("ASR", I_ASR, OC_1GEN, &instruction_section, &system_st);
add_sym("LSL", I_LSL, OC_1GEN, &instruction_section, &system_st);
add_sym("LSR", I_LSR, OC_1GEN, &instruction_section, &system_st);
add_sym("BCC", I_BCC, OC_BR, &instruction_section, &system_st);
add_sym("BCS", I_BCS, OC_BR, &instruction_section, &system_st);
Последний раз редактировалось Bill_ Сб апр 01, 2023 08:23:02, всего редактировалось 1 раз.
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Связанный свитер, а список связный. А так, в целом верно. Разве что, память не только в куче можно взять.
- Сообщения: 60
- Зарегистрирован: Вс ноя 13, 2022 14:58:17
[uquote="VladislavS",url="/forum/viewtopic.php?p=4394562#p4394562"]Связанный свитер, а список связный. А так, в целом верно. Разве что, память не только в куче можно взять.[/uquote]
Исправил.
Исправил.
Ну, это всё понятно. пополнение списка у меня не предполагается. потому как это не настоящий форт, а всего-лишь способ интерпретации команд. Очень простой, причем. Почему я кошусь в сторону списков? Хочется избавиться от ограничения на длину строки. Для интерпретатора нуль-терминированная строка вполне подходит (тем более что у меня сейчас это сделано также - сравнение либо до '\0', либо до 12-го символа). Но массив, как вы сказали, имеет жёстко заданные размеры. И для того чтобы иметь возможность с этим справиться и может помочь список. Почему меня не устраивает применение "add_sym()" - из-за того, что тогда этот "список" будет в двух местах и в ПЗУ, и в ОЗУ. И еще нужно будет ждать пока он проиницализируется при старте.
- Реклама
- Сообщения: 60
- Зарегистрирован: Вс ноя 13, 2022 14:58:17
[uquote="uldemir",url="/forum/viewtopic.php?p=4394571#p4394571"]Ну, это всё понятно. пополнение списка у меня не предполагается. потому как это не настоящий форт, а всего-лишь способ интерпретации команд. Очень простой, причем. Почему я кошусь в сторону списков? Хочется избавиться от ограничения на длину строки. Для интерпретатора нуль-терминированная строка вполне подходит (тем более что у меня сейчас это сделано также - сравнение либо до '\0', либо до 12-го символа). Но массив, как вы сказали, имеет жёстко заданные размеры. И для того чтобы иметь возможность с этим справиться и может помочь список. Почему меня не устраивает применение "add_sym()" - из-за того, что тогда этот "список" будет в двух местах и в ПЗУ, и в ОЗУ. И еще нужно будет ждать пока он проиницализируется при старте.[/uquote]
Используйте в элемента не массив символов, а указатель на него. Например, вместо
Хотя инициализация массива будет выглядеть одинаково.
Используйте в элемента не массив символов, а указатель на него. Например, вместо
Код: Выделить всё
char word[12];Код: Выделить всё
char *word;- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
[uquote="uldemir",url="/forum/viewtopic.php?p=4394571#p4394571"]Почему я кошусь в сторону списков? Хочется избавиться от ограничения на длину строки.[/uquote]У вас не хватает памяти? Пусть у вас три десятка элементов в среднем занятых на половину. 30х6=180 байт лишних. Вы уверены, что функции работы со связным списком займут меньше? Пока что это выглядит как преждевременная оптимизация.
В своё время (лет эдак 30 назад) Харий Буш говорил про винчестеры, что скорость их заполнения является константой и от объёма диска независящая. Так же и с памятью. Когда-то хватало 4 килобайт, сейчас и в 128 становится тесно. Хотя новый проект идёт на кристалле с 1.5М флеша и 0.5М озу. Но если серьёзно, хочется научиться разным техникам просто из интереса. И честно, мне плевать, сколько это памяти съест, а как это внятно написать в программе, чтобы было легче её "сопровождать". Я мог бы оставить строку с ограниченной длинной, и когда мне захотелось бы добавить слово "init_brakepath" тогда пришлось бы думать, сократить эту команду на 2 символа или в определении поменять 12 на 14. А так, я даже еще потерял 4 байта памяти на указатель к строке, но зато можно не ломать голову что делать.
Спойлер
Собственно, всё это началось с того, что взяв проект двухлетней давности я не мог вспомнить, как пользоваься некоторыми командами и поэтому захотелось добавить команду "help", которая мне напомнила бы, как та или иная команда работает. Т.е. help переключает контекст и команда init_brakepath не инициализирует таблицу тормозного пути, а рассказывает, что она будет делать. Так что важнее читаемость программы для дальнейшей модификации, а не объём памяти (хотя его тоже нельзя брасывать со счёт). Читаю тут что на C++ это можно делать гораздо продвинутей, но я еще сам не настолько продвинутПосмотрите, как делал я в своём проекте FlexMenu, там на этапе компиляции собираются массивы со строковыми константами произвольной длины. Там, кстати, есть и еще некоторые моменты, которые, как мне кажется, могут вам пригодиться. Если с макросами разберетесь, конечно...
А из проекта DigiScript можете использовать идею "массивов без явного описания и с инициализацией элементов в любом месте проекта". В этом проекте, кстати, я как раз интерпретатор и делал.
А из проекта DigiScript можете использовать идею "массивов без явного описания и с инициализацией элементов в любом месте проекта". В этом проекте, кстати, я как раз интерпретатор и делал.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Красивого решения для работы со строковыми литералами на этапе компиляции нет даже в С++. Каждый раз решение под задачу приходится придумывать. Где-то память важна, где-то скорость доступа. Для USB-дескрипторов, например, вот так делаю.
1. Под каждый литерал глобальная структура. Макросы зло, но шаблоны и строковые литералы плохо дружат. Так что, пока макрос.

2. Набиваем глобальных объектов

3. Создаём массив указателей на глобальные объекты. Причём, тут даже жертвуем типизацией.

4. Например, поиск в такой "структуре" по индексу

И никакие связные списки для константных данных этапа компиляции, само собой, тут не нужны. Каждый инструмент предназначен для своих задач.
1. Под каждый литерал глобальная структура. Макросы зло, но шаблоны и строковые литералы плохо дружат. Так что, пока макрос.
2. Набиваем глобальных объектов
3. Создаём массив указателей на глобальные объекты. Причём, тут даже жертвуем типизацией.
4. Например, поиск в такой "структуре" по индексу
И никакие связные списки для константных данных этапа компиляции, само собой, тут не нужны. Каждый инструмент предназначен для своих задач.
Спойлер
Вопрос по ардуине. Есть функция в файле motors.cpp
вызывается просто:
Я бы подумал, что установится частота 488Гц. Но в хидере она объявлена так:
Это что значит? в плюсах я ничего не понимаю.
Код: Выделить всё
void set_motor_pwm_frequency(int frequency) {
switch (frequency) {
case PWM_31250_HZ:
// Divide by 1. frequency = 31.25 kHz;
...
break;
case PWM_3906_HZ:
// Divide by 8. frequency = 3.91 kHz;
...
break;
case PWM_488_HZ:
default:
// Divide by 64. frequency = 488Hz;
...
break;
}
}Код: Выделить всё
set_motor_pwm_frequency();Код: Выделить всё
/***
* @brief set the motor pwn drive to one of three possible values
*/
void set_motor_pwm_frequency(int frequency = PWM_31250_HZ);
"аргумент по умолчанию" - если ничего в аргументах не указывается пользователем будет использовано значение по умолчанию.

- Сообщения: 1407
- Зарегистрирован: Вт июн 07, 2011 08:03:18
[uquote="uldemir",url="/forum/viewtopic.php?p=4409235#p4409235"]Но в хидере...[/uquote]
Не в хидере, а в хедере! "Карту купи..."
Не в хидере, а в хедере! "Карту купи..."
- Сообщения: 12867
- Зарегистрирован: Сб дек 18, 2021 19:25:32
ну, тогда уж правильно в хеде, без р
Лучше бы по делу что написали, что произойдёт, если этот хи... пусть будет так: motors.h не будет включен в motors.cpp.
- Сообщения: 12867
- Зарегистрирован: Сб дек 18, 2021 19:25:32
ну как что? если заголовочный файл не будет подключен, область видимости объявленных в нем переменных и функций и значения дефайнов изменятся. В случае переменных и функций будет фатальная ошибка (впрочем, с функциями не всегда), в случае дефайнов - или фатальная, или логическая (если они где-то ещё такие же есть, но с другими значениями).
Здесь, если компилятор увидит функцию раньше вызова, ошибки не будет, но значение по умолчанию потеряется.
Здесь, если компилятор увидит функцию раньше вызова, ошибки не будет, но значение по умолчанию потеряется.
- Сообщения: 81
- Зарегистрирован: Пт май 14, 2021 22:25:07
Я вижу тут народ списки обсуждал. TL;DR.
Чем не устраивает плюсовый std::list? Список, конечная самая простая из сложных структур данных, но реализовывать функции для работы с ней с нуля муторно.
Кстати, совет, можно написать список полностью в максросах (как шаблоны на Си++) и тогда можно будет не копипастить их для разных типов данных.
Чем не устраивает плюсовый std::list? Список, конечная самая простая из сложных структур данных, но реализовывать функции для работы с ней с нуля муторно.
Кстати, совет, можно написать список полностью в максросах (как шаблоны на Си++) и тогда можно будет не копипастить их для разных типов данных.
- Сообщения: 145
- Зарегистрирован: Пн апр 02, 2012 15:56:23
[uquote="zx_gamer",url="/forum/viewtopic.php?p=4412126#p4412126"]Чем не устраивает плюсовый std::list?[/uquote]
Думаю, что не ошибусь, если скажу, что среднему программисту гораздо проще написать свою реализацию списка (хоть на си, хоть на плюсах с шаблонами), чем свой кастомный аллокатор для STL-контейнеров.
Думаю, что не ошибусь, если скажу, что среднему программисту гораздо проще написать свою реализацию списка (хоть на си, хоть на плюсах с шаблонами), чем свой кастомный аллокатор для STL-контейнеров.
Снова глупый вопрос. Для расчета тормозного пути мне надо вычислить разность квадратов a²-b². В целочисленных вычислениях я использовал формулу (a-b)*(a+b) - два сложения и одно умножение. А как лучше считать для плавующей точки, если у процессора есть FPU? имеется в виду - два умножения и сложение или два сложения и умножение - что будет быстрее.
Имхо, умножение однотактное маловероятно даже на FPU, а сложение однозначно однотактное.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!


