Вопросы по С/С++ (СИ)

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Нет, не знаю зачем тут typedef.
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

WiseLord, это потому что у тебя задан -fshort-enums, а 555 в байт не влазит, замени на 55, ворнинг пропадет.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

[uquote="WiseLord",url="/forum/viewtopic.php?p=3711331#p3711331"]Да и битовые поля это не совсем стандарт.[/uquote]
Что значит "не совсем стандарт"?
Читаем стандарт С11 "6.7.2.1 Structure and union specifiers"
Друг Кота
Аватара пользователя
Сообщения: 4906
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Мне всегда казалось, что для uint8_t (char) битовые поля - это расширение GCC. Возможно, в C11 их для большего числа типов расширили.
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

WiseLord, в первом стандарте C, с которым я общался это уже было. Смотрим ISO/IEC 9899: 1990 (С89/C90) на странице 60.

P.S. Помнится, даже у Кернигана и Ритчи битовые поля были )
Реклама
Друг Кота
Аватара пользователя
Сообщения: 4906
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Оно просто не для всех типов было. А для тех, которые я юзал (uint8_t) - подсвечивалось в IDE как расширение gcc (clang-овский статический анализатор в QtCreator)
Контактная информация:
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

WiseLord, uint8_t - определяется в stdint.h как typedef unsigned char uint8_t;
В стандарт stdint.h и uint8_t действительно попал только в C99. Но 20 лет назад - тоже немало )
Друг Кота
Аватара пользователя
Сообщения: 4906
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Я не совсем про то. Я про то, что битовые поля стандартны для int и _Bool типов, а вот для однобайтных (char, unsigned char) - это как бы не по стандарту, но работает как расширение gcc.
Контактная информация:
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

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

Но на работе в голове покрутил проблему и... всё не так просто.

Сначала у меня был тип данных dir_t - вправо, влево, вперед, назад. Всё было хорошо. это для робота в лабиринте. Но тут взбрело мне еще выяснить, а где именно я нахожусь. Поэтому придумалось иметь направление. Поэтому и ввёл этот motion_t. И задача выяснить, куда я поеду, если я ехал на север и повернул налево. Но тут я понял, что два разных типа я суммировать не могу, а делать switch/case на каждую комбинацию - можно повеситься. Поэтому я сейчас объединил эти два типа. Т.е.

Код: Выделить всё

typedef enum {
	straight = 0, 
	right = 1, 
	back = 2, 
	left = 3
} t_dir;
#define	north	straight 
#define	east 	right 
#define	south	back 
#define	west 	left
Так что теперь, я их просто суммирую и надо бы еще и обрезать. Причем если эти операции делать отдельно:

Код: Выделить всё

				move_direction += turn_direction;
				move_direction &= 0x03;
всё компилируется без предупреждений, а если сделать хором, как в исходном сообщении - получаю предупреждение о mixed type.

Мммм, как-то на ардуине делал календарь, так там для типа месяца нашел в интернете и сделал так:

Код: Выделить всё

month_t operator ++( month_t &id, int )
{
   month_t current = id;

   if ( december < id + 1 ) id = january;
   else id = static_cast<month_t>( id + 1 );

   return ( current );
}
Но это, возможно, C++ конструкция. И мне унарного инкремента недостаточно.

дефайнами пользоваться не хочу - хочу использовать выразительные средства языка. Компилю Keil uVision.
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

WiseLord, тут Вы правы, но, по стандарту, при длине битового поля до 8 бит включительно, результат unsigned char i:2 и unsigned int i:2 - одинаков. Я просто по привычке использовал наиболее короткий тип, как дополнительную защиту от ошибки.
В стандарте же сказано только, что "An implementation may allocate any addressable storage unit large enough to hold a bitfield."
Друг Кота
Сообщения: 3092
Зарегистрирован: Пн апр 06, 2015 11:01:53
Откуда: москва, уфа

Сообщение arkhnchul »

[uquote="uldemir",url="/forum/viewtopic.php?p=3711476#p3711476"]Но тут я понял, что два разных типа я суммировать не могу[/uquote]почему нет? C позволяет весьма вольно обращаться с энумами. Вы, случаем, не компилятором C++ свой код собираете?)
[uquote="uldemir",url="/forum/viewtopic.php?p=3711476#p3711476"]Поэтому я сейчас объединил эти два типа.[/uquote]весьма спорное с точки зрения читабельности кода решение. Я бы делал что-то типа того (оно вполне собирается и работает)
Спойлер

Код: Выделить всё

typedef enum  {
	ROTATION_NONE = 0,
	ROTATION_RIGHT = 1,
	ROTATION_BACKWARD = 2,
	ROTATION_LEFT = 3
} rotation_dir_t;

typedef enum {
	BEARING_NORTH = 0,
	BEARING_EAST = 1,
	BEARING_SOUTH = 2,
	BEARING_WEST = 3
} bearing_dir_t;

bearing_dir_t compute_bearing(bearing_dir_t current_bearing, rotation_dir_t rotation){
	return (bearing_dir_t)(current_bearing + rotation) & 0x03;
}
[uquote="uldemir",url="/forum/viewtopic.php?p=3711476#p3711476"]Но это, возможно, C++ конструкция[/uquote]да, перегрузка операторов - фича плюсов.
Друг Кота
Аватара пользователя
Сообщения: 7383
Зарегистрирован: Пт авг 28, 2009 21:34:30
Откуда: 845-й км.

Сообщение uldemir »

Собирается, но даёт предупреждение.

Код: Выделить всё

*** Using Compiler 'V5.06 update 6 (build 750)', folder: 'C:\Keil_v5\ARM\ARMCC\Bin'
compiling Maze.c...
Maze.c(57): warning:  #188-D: enumerated type mixed with another type
     return (bearing_dir_t)(current_bearing + rotation) & 0x03;
Maze.c: 1 warning, 0 errors
"Maze.c" - 0 Error(s), 1 Warning(s).
Мне хочется избежать предупреждений.

Ну, в принципе, да - надо заниматься приведением типов... такое компилируется, почему-то без предупреждений:

Код: Выделить всё

bearing_dir_t compute_bearing(bearing_dir_t current_bearing, rotation_dir_t rotation){
	bearing_dir_t next_bearing;
	next_bearing = (bearing_dir_t)(current_bearing + rotation);
	return next_bearing &= 0x03;
}
А люди посмотрят и скажут: "Собаки летят. Вот и осень."
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18790
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

имхо: избавляться от варнингов нет необходимости, если они на самом деле являются следствием реализации алгоритма. варнинг говорит о том, что мнение компилятора и программиста по данному вопросу МОГУТ расходиться, но не факт, что это представляет проблему. приведение типа в данном случае является страусиной политикой: не вижу, значит, это не существует. а это заведомо хуже, чем вижу, но не боюсь, ибо...

то же самое с битовыми полями. я вижу в этом большой минус: отсутствие явного маскирования искажает алгоритм работы, и вводит в заблуждение. если алгоритм не просматривается по коду - это, с моей точки зрения, плохо.

для полностью "прозрачной" реализации я бы сделал как-то так:

Код: Выделить всё

typedef enum{
   DIR_FIRST,
// добавлять ниже, но не выше!
   DIR_NORD,
   DIR_EAST,
   DIR_SOUTH,
   DIR_WEST,
// ниже не добавлять!
   DIR_LAST
} direction_t;

direction_t rotate_right(direction_t current_dir){
   if(++current_dir >= DIR_LAST) current_dir = DIR_FIRST + 1;
   return current_dir;
}

direction_t rotate_left(direction_t current_dir){
   if(--current_dir == DIR_FIRST) current_dir = DIR_LAST - 1;
   return current_dir;
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Мудрый кот
Сообщения: 1842
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="ARV",url="/forum/viewtopic.php?p=3711791#p3711791"]имхо: избавляться от варнингов нет необходимости, если они на самом деле являются следствием реализации алгоритма. варнинг говорит о том, что мнение компилятора и программиста по данному вопросу МОГУТ расходиться, но не факт, что это представляет проблему. приведение типа в данном случае является страусиной политикой: не вижу, значит, это не существует. а это заведомо хуже, чем вижу, но не боюсь, ибо...[/uquote]
В корне неправильно!
От варнингов нужно избавляться всегда. Если Ваше мнение расходится с мнением компилятора хуже будет только вам. Потому что компилятор сделает по-своему. Он вас предупредил, Вы проигнорили - дальше виноваты сами за последствия.
Если на вас едет паровоз, машинист видит вас и предупреждает гудком чтобы Вы ушли с рельс. Если вы это проигнорите - паровозу от этого не поплохеет. Ну разве что скотоотбойник запачкает :)))

А как именно избавляться - это уже можно делать по-разному.
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

jcxz, тут я с Вами не согласен. Простейший пример. Имеем таблицу указателей на функции. Пусть у функции один параметр. Причем части функций этот параметр просто не нужен, хотя остальные функции без него обойтись не могут. Получаем два варианта решения:
1. Игнорируем конкретное предупреждение о неиспольуемом значении параметра:

Код: Выделить всё

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
...
#pragma GCC diagnostic pop
2. Усложняем алгоритм, разбивая таблицу на две и выполняя поиск нужного обработчика в обоих таблицах.

Пример:

Код: Выделить всё

typedef struct ir_cmd_st {
  uint8_t   code;
  uint8_t (*ir_handler)(uint8_t);
} ir_cmd_t;

static ir_cmd_t ir_cmd_table[] = {
  { IR_NEC_CMD_UP,    ir_handler_brightness },
  { IR_NEC_CMD_DOWN,  ir_handler_brightness },
  { IR_NEC_CMD_LEFT,  ir_handler_pgm_prev},
  { IR_NEC_CMD_RIGHT, ir_handler_pgm_next},
  { IR_NEC_CMD_OK,    ir_handler_switch_channel},
  { IR_NEC_CMD_0,     ir_handler_pgm_no},
  { IR_NEC_CMD_1,     ir_handler_pgm_no},
  { IR_NEC_CMD_2,     ir_handler_pgm_no},
  { IR_NEC_CMD_3,     ir_handler_pgm_no},
  { IR_NEC_CMD_4,     ir_handler_pgm_no},
  { IR_NEC_CMD_5,     ir_handler_pgm_no},
  { IR_NEC_CMD_6,     ir_handler_pgm_no},
  { IR_NEC_CMD_7,     ir_handler_pgm_no},
  { IR_NEC_CMD_8,     ir_handler_pgm_no},
  { IR_NEC_CMD_9,     ir_handler_pgm_no} };
Здесь обработчками ir_handler_pgm_prev(), ir_handler_pgm_next() и ir_handler_switch_channel() код нажатой кнопки на ИК пульте совершенно не нужен, тогда как обработчиками ir_handler_brightness() и ir_handler_pgm_no() он необходим.
Держит паяльник хвостом
Аватара пользователя
Сообщения: 960
Зарегистрирован: Вс дек 02, 2012 16:58:33
Откуда: от туда

Сообщение GARMIN »

Не знаю, насколько кошерно было моё решение, но я в подобном случае обьявлял статическую переменную с параметром команды. Или в моём случае статическую структуру с несколькими параметрами. Так я избавился от неоднозначности вызова.
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

GARMIN, например, на SDCС и STM8S, для которого был использован данный код, Ваш подход приведет к дополнительным машинным командам в каждом обработчике, которому нужен код клавиши. Тогда как в моем случае, код клавиши сразу оказывается в аккумуляторе, где он и был в вызывающей программе при поиске обработчика в таблице. Мне даже в память этот код не нужно сохранять.

К тому же, это простейший пример. А бывают таблицы куда более сложных обработчиков. При этом, если у меня выбор между лишней pragma и потреблением дополнительной памяти в статическом сегменте SRAM, я выберу первое )
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

ПростоНуб, вызываешь с параметром функцию без параметров? И эти люди запрещают мне перегрузку :)
Собутыльник Кота
Аватара пользователя
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01

Сообщение Eddy_Em »

Убрал.
Нарушение Правил форума п. 2.3
aen
Контактная информация:
Собутыльник Кота
Аватара пользователя
Сообщения: 2723
Зарегистрирован: Пт сен 07, 2018 20:20:02
Откуда: деревня в Тульской губернии

Сообщение ПростоНуб »

VladislavS, Вы как всегда не в теме )))
В массиве указателей на функцию все функции должны быть с одинаковым возвращаемым значением и с одинаковым набором параметров. Поэтому, если каким-то из этих функций нужен для алгоритма параметр, то его приходится передавать всем функциям в этом массиве.
То есть, тут и близко не пахнет перегрузкой. Это разные функции выполняющие разные действия при возникновении подобных событий. В данном случае - нажатии разных кнопок на одном и том же пульте ДУ на ИК лучах.
Ответить

Вернуться в «Разные вопросы по МК»