Страница 326 из 386

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

Добавлено: Ср окт 02, 2019 10:40:40
Eddy_Em
[uquote="VladislavS",url="/forum/viewtopic.php?p=3711253#p3711253"][uquote="Eddy_Em",url="/forum/viewtopic.php?p=3711208#p3711208"]задефайните основные направления,[/uquote]Ну он это и сделал enum-ом.[/uquote]
Ну так UB же! В общем случае нельзя enum'ом, если значение за пределы enum'а может выходить — мало ли какой компилятор попадется... Надежней дефайнами.

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

Добавлено: Ср окт 02, 2019 11:27:39
VladislavS
Надёжней enum class.

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

Добавлено: Ср окт 02, 2019 11:28:23
Eddy_Em
Кресты надежней С? Не надо смешить мои тапочки!

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

Добавлено: Ср окт 02, 2019 11:34:00
ПростоНуб
Eddy_Em, так красивей:

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

#define DIRECTION_NORD 0
#define DIRECTION_EAST 1
#define DIRECTION_SOUTH 2
#define DIRECTION_WEST 3

typedef struct directions_st {
  uint8_t direction:2;
} directions_t;

directions_t rotate(directions_t dir, int8_t  angle){
  dir.direction+=angle;
  return dir;
}
или даже без функции

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

#define DIRECTION_NORD 0
#define DIRECTION_EAST 1
#define DIRECTION_SOUTH 2
#define DIRECTION_WEST 3

#define DIRECTION_STEP_LEFT(d) d.direction--
#define DIRECTION_STEP_RIGHT(d) d.direction++

typedef struct directions_st {
  uint8_t direction:2;
} directions_t;

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

Добавлено: Ср окт 02, 2019 11:34:34
VladislavS
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=3711320#p3711320"]Кресты надежней С? Не надо смешить мои тапочки![/uquote]Да ты хоть почитай что это, а потом лужи газируй.

Зачем тут слово typedef? Красивое?

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

Добавлено: Ср окт 02, 2019 11:41:08
Eddy_Em
ПростоНуб, в данном случае - да. Красивое решение. Разве что неудобно, что переменной постоянно нужно еще и поле .direction дописывать... Зато проверка на выход за пределы диапазона автоматом...
VladislavS, сам знаешь, зачем нужен typedef! Не выпендривайся!

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

Добавлено: Ср окт 02, 2019 11:45:02
Reflector
[uquote="Eddy_Em",url="/forum/viewtopic.php?p=3711320#p3711320"]Кресты надежней С? Не надо смешить мои тапочки![/uquote]
На С можно написать:

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

typedef enum { north, east, south, west } Dir;

Dir dir = 555;
dir /= 111;
И это замечательно работает, на gcc c "-Wall -Wextra" даже предупреждения не выдает. Странно, что тебе это кажется нормой учитывая, что тут якобы есть UB :)

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

Добавлено: Ср окт 02, 2019 11:48:25
WiseLord
Eddy_Em, для 4 значений (степень двойки) работать будет, для произвольного числа уже нет. Да и битовые поля это не совсем стандарт. Но вообще, да, выглядит красивее, чем деление с остатком.

Reflector, -Werror:

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

arm-none-eabi-gcc -c -mcpu=cortex-m3 -mthumb   -DUSE_FULL_LL_DRIVER -DSTM32F103xB -D_STM32F1 -D_ILI9341 -D_DISP_SPI -D_DISP_320x240 -D_TDA7439 -D_TDA731X -D_PT232X -D_TDA7418 -D_RDA580X -D_SI470X -D_TEA5767 -Idisplay -Iusb -Idrivers/STM32F1xx_HAL_Driver/Inc -Idrivers/STM32_USB_Device_Library/Core/Inc -Idrivers/CMSIS/Device/ST/STM32F1xx/Include -Idrivers/CMSIS/Include -Isystem -Os -fshort-enums -ffunction-sections -fdata-sections -ffreestanding -Wall -Werror -g -gdwarf-2 -MMD -MP -MT build/main.o -MF build/./main.d -DUSE_FULL_LL_DRIVER -DSTM32F103xB -D_STM32F1 -D_ILI9341 -D_DISP_SPI -D_DISP_320x240 -D_TDA7439 -D_TDA731X -D_PT232X -D_TDA7418 -D_RDA580X -D_SI470X -D_TEA5767 -o build/main.o main.c
main.c: In function 'main':
main.c:112:15: error: unsigned conversion from 'int' to 'Dir' {aka 'enum <anonymous>'} changes value from '555' to '43' [-Werror=overflow]
     Dir dir = 555;
               ^~~
cc1: all warnings being treated as errors
P.S. c -Wextra без -Werror компилирует, но с предупреждениями.

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

Добавлено: Ср окт 02, 2019 11:50:19
VladislavS
Нет, не знаю зачем тут typedef.

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

Добавлено: Ср окт 02, 2019 11:52:47
Reflector
WiseLord, это потому что у тебя задан -fshort-enums, а 555 в байт не влазит, замени на 55, ворнинг пропадет.

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

Добавлено: Ср окт 02, 2019 11:56:11
ПростоНуб
[uquote="WiseLord",url="/forum/viewtopic.php?p=3711331#p3711331"]Да и битовые поля это не совсем стандарт.[/uquote]
Что значит "не совсем стандарт"?
Читаем стандарт С11 "6.7.2.1 Structure and union specifiers"

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

Добавлено: Ср окт 02, 2019 12:00:59
WiseLord
Мне всегда казалось, что для uint8_t (char) битовые поля - это расширение GCC. Возможно, в C11 их для большего числа типов расширили.

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

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

P.S. Помнится, даже у Кернигана и Ритчи битовые поля были )

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

Добавлено: Ср окт 02, 2019 12:47:32
WiseLord
Оно просто не для всех типов было. А для тех, которые я юзал (uint8_t) - подсвечивалось в IDE как расширение gcc (clang-овский статический анализатор в QtCreator)

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

Добавлено: Ср окт 02, 2019 13:59:19
ПростоНуб
WiseLord, uint8_t - определяется в stdint.h как typedef unsigned char uint8_t;
В стандарт stdint.h и uint8_t действительно попал только в C99. Но 20 лет назад - тоже немало )

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

Добавлено: Ср окт 02, 2019 14:49:25
WiseLord
Я не совсем про то. Я про то, что битовые поля стандартны для int и _Bool типов, а вот для однобайтных (char, unsigned char) - это как бы не по стандарту, но работает как расширение gcc.

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

Добавлено: Ср окт 02, 2019 16:05:25
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.

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

Добавлено: Ср окт 02, 2019 20:36:13
ПростоНуб
WiseLord, тут Вы правы, но, по стандарту, при длине битового поля до 8 бит включительно, результат unsigned char i:2 и unsigned int i:2 - одинаков. Я просто по привычке использовал наиболее короткий тип, как дополнительную защиту от ошибки.
В стандарте же сказано только, что "An implementation may allocate any addressable storage unit large enough to hold a bitfield."

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

Добавлено: Ср окт 02, 2019 21:51:02
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]да, перегрузка операторов - фича плюсов.

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

Добавлено: Чт окт 03, 2019 03:50:49
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;
}