DetSimen и битовые поля

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Всё-таки в С я плаваю.  И не просто плаваю, а плаваю как утяжеленный топор без ручки с привареным урановым ломом. 

В одном праэктике есть структура с битовыми полями, один из байтиков которой описан как 

	bool SWP1 : 1;			// установить software port 1 в 0/1 (в китайских модулях вещь бесполезная)
	bool MuteLeft : 1;		// выключить левый канал
	bool MuteRight : 1;		// выключить правый канал
	bool Mono : 1;			// Установить принудительно режим Моно
	enumHSLI HSLI : 1;			// High/Low Side Injection = false/true  Low = true
	enumSearchStopLevel AutoSearchLevel : 2;  // уровень сигнала станции для остановки автопоиска 
	bool SearchUp : 1;		// true - автопоиск будет искать вверх по частоте, false - вниз 

enum-ы описаны как 

enum class enumHSLI: bool {HiSide=false, LowSide=true};  // High/Low side injection гетеродин выше/ниже несущей  

//--------------------------------------------------------------------------------
// уровень сигнала станции для остановки автопоиска
//
// Not Allowed	- запрещенная комбинация
// Leak			- поиск станций с низким уровнем сигнала
// Medium		- поиск станций со средним уровнем сигнала
// Strong		- поиск только сильных, ближайших станций

enum class enumSearchStopLevel: uint8_t {NotAllowed=0, Leak=1, Medium=2, Strong=3};

всё компилируеца, канеш, но анажды, что-то подсказало мне включить warning-и при компиляции.  Теперь битовые поля, описанные как bool, и даже enumHSLI  вопросов не вызывает, а на enumSearchStopLevel канпилятор ругаеца от так 

warning: 'T5767Output::AutoSearchLevel' is too small to hold all values of 'enum class enumSearchStopLevel
  enumSearchStopLevel AutoSearchLevel *: 2;
 
и вроде бы 2 бита хватает, чтобы хранить значения от 0 до 3, пошто канпилятор такой суровый?  Какие ошибки меня ждут при таком использовании enum class и как избавить меня от этих warning-ов. 
b707
Онлайн
Зарегистрирован: 26.05.2017

DetSimen пишет:

enum-ы описаны как 

enum class enumSearchStopLevel: uint8_t {NotAllowed=0, Leak=1, Medium=2, Strong=3};
 
и вроде бы 2 бита хватает, чтобы хранить значения от 0 до 3, пошто канпилятор такой суровый?  Какие ошибки меня ждут при таком использовании enum class и как избавить меня от этих warning-ов. 

конечно too smal - ты ж enum описал размером в uint8_t

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

b707 пишет:

конечно too smal - ты ж enum описал размером в uint8_t

дак а по другому не опишешь, или опишешь? Тогда как? 

если написать , допустим 

uint8_t SignalLevel:4;  

то все будет намайно, без ошибок, значения будуть 0-15, хотя тип тоже описан как целый байт

b707
Онлайн
Зарегистрирован: 26.05.2017

Поискал в СтекОверфлоу - пишут. что эта проблема решения не имеет?

"in C it is an undefined behavior, because a bit-field can only have signed int or unsigned int or bool types"

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

мда. 

sadman41
Offline
Зарегистрирован: 19.10.2016

Для того, чтобы тебе правильно вписаться в структуру, нужен enum в 2 бита. Но размерность enum может задаваться только базовыми типами, самый маленький из которых - 8 бит.

Так что или enum на 8 бит или 2 бита и дефайны.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

Дед, во многих знаниях, много печали. Вот будь на Вашем месте кто-то, действительно плохо знающий язык (а не прибедняющийся, как Вы), у него бы не было проблем потому, что он не стал бы делать типизированный enum, а для нетипизированного этой проблемы не возникает от слова совсем - компилятор сам разбирается с его размером.

DetSimen пишет:
Тогда как?

Вот смотрите:

enum class enumHSLI: bool {HiSide=false, LowSide=true};  // High/Low side injection гетеродин выше/ниже несущей  
enum  enumSearchStopLevel {NotAllowed=0, Leak=1, Medium=2, Strong=3};

union MyUnion {
	uint8_t byteBase;
	struct {
		bool SWP1 : 1;			// установить software port 1 в 0/1 (в китайских модулях вещь бесполезная)
		bool MuteLeft : 1;		// выключить левый канал
		bool MuteRight : 1;		// выключить правый канал
		bool Mono : 1;			// Установить принудительно режим Моно
		enumHSLI HSLI : 1;			// High/Low Side Injection = false/true  Low = true
		enumSearchStopLevel AutoSearchLevel : 2;  // уровень сигнала станции для остановки автопоиска 
		bool SearchUp : 1;
	};
};	

void setup(void){
	Serial.begin(57600);
	Serial.print("sizeof(MyUnion)=");
	Serial.println(sizeof(MyUnion));
	//
	MyUnion kaka;
	kaka.byteBase = 0;
	kaka.AutoSearchLevel = Strong;
	Serial.print("kaka=");
	Serial.println(kaka.byteBase, HEX);

}

void loop(void){}

Никаких предупреждений - всё пучком. Результат

sizeof(MyUnion)=1
kaka=60

Так что всё правильно работает.

Причем, заметьте (это важно!) компилятор именно разбирается, а не просто "плюёт на возможную ошибку"! В этом легко убедиться - достаточно в строке 2 перед "}" добавить, например, ", EvenStronger=4". После этого двухбитовое поле реально окажется маленьким и сообщение, о котором Вы говорили, появится вновь. Так что он реально смотрит и предупреждает.

DetSimen
DetSimen аватар
Онлайн
Зарегистрирован: 25.01.2017

Спасибо за науку.  

Просто чем хорош типизированный enum, тем, что его константы имеют область видимости, ограниченную внутри самого enum-а. Т.е два или три или больше enum-ов в одном файле могут иметь одинаково поименованные константы внутри себя, что в обычных enum-ах, нетипизированных, вопщем-та, не допускаеца (но это не точно).  Обращение, конечно, к типизированному enum-у приходится писать дольше, зато перепутать константы, относящиеся к разным enum-ам нельзя.

В кристально чесном С, которого полно у Onkel-я, я этого не помню, памойму это уже позднее благоприобретение, слизанное с Шарпа.  Но вот почему бы не сделать еще шажок, чтоб срастить эту удобную канструкцию с битовыми полями...  Ну это я так, ворчу.   

В любом случае, спасибо ЕвгенийП, информацию я впитал. :)  Буду воспринимать это как данность, правда, с горестным недоумением.  (и штозаязыктакой, и кто его только придумал, и где сечас эти люди? ну и по традиции, наданапица)

Green
Offline
Зарегистрирован: 01.10.2015

А так?

typedef enum {NotAllowed, Leak, Medium, Strong} enumSearchStopLevel;

 

a5021
Offline
Зарегистрирован: 07.07.2013

Мож не Leak, а Weak ? Тока щас увидел.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

a5021 пишет:

Мож не Leak, а Weak ? Тока щас увидел.

Leak - тоже ничего, "утечка" - "слабенько" :-)))

Green
Offline
Зарегистрирован: 01.10.2015

Не придирайтесь к словам.)

a5021
Offline
Зарегистрирован: 07.07.2013

ЕвгенийП пишет:
Leak - тоже ничего,

Еще как! Особенно в контексте to take a leak -- справить малую нужду. :) Варианты leak/medium/strong в этом случае порождают какие-то неуловимые ассоциации. :)

qwone
qwone аватар
Offline
Зарегистрирован: 03.07.2016

a5021 пишет:

 

Еще как! Особенно в контексте to take a leak -- справить малую нужду. :) Варианты leak/medium/strong в этом случае порождают какие-то неуловимые ассоциации. :)

Ну похоже to piss Вы в английском отменили.

a5021
Offline
Зарегистрирован: 07.07.2013

Ничего не отменял. Как и в русском, одно и то же там можно выразить по разному. По поводу нюансов, прошу в гугл.

ЕвгенийП
ЕвгенийП аватар
Offline
Зарегистрирован: 25.05.2015

qwone пишет:
похоже to piss Вы в английском отменили.
Да, нет, это Вы отменили в русском "отлить".