В этом сообщении на Quora я видел следующий код :
#include <stdio.h>
struct mystruct { int enabled:1; };
int main()
{
struct mystruct s;
s.enabled = 1;
if(s.enabled == 1)
printf("Is enabled\n"); // --> we think this to be printed
else
printf("Is disabled !!\n");
}
Как в C, так и в C ++ вывод кода является неожиданным ,
Выключен !!
Хотя объяснение, связанное с «битом знака», дается в этом посте, я не могу понять, как это возможно, что мы что-то устанавливаем, а затем это не отражает как есть.
Может кто-нибудь дать более подробное объяснение?
Примечание : оба тегаc & c ++являются обязательными, потому что их стандарты немного отличаются для описания битовых полей. См ответы спецификации C и спецификации C ++ .
int
я думаю, оно может содержать только значения0
и-1
.struct mystruct { unsigned int enabled:1; };
?Ответы:
Битовые поля невероятно плохо определены стандартом. Учитывая этот код
struct mystruct {int enabled:1;};
, мы не знаем:int:n
Следует ли рассматривать битовое поле как подписанное или беззнаковое.Что касается последней части, C17 6.7.2.1/10 говорит:
Ненормативное примечание, поясняющее вышеуказанное:
В случае, если битовое поле должно рассматриваться как
signed int
и вы делаете немного размера1
, тогда нет места для данных, только для бит знака. Это причина, по которой ваша программа может давать странные результаты на некоторых компиляторах.Хорошая практика:
int
типа для любых форм битовых манипуляций.источник
Вы спрашиваете, почему он компилируется vs. дает вам ошибку?
Да, в идеале он должен выдать ошибку. И это так, если вы используете предупреждения вашего компилятора. В GCC с
-Werror -Wall -pedantic
:Обоснование того, почему это оставлено на усмотрение реализации, а не ошибка, может иметь больше отношения к историческому использованию, где требование приведения означало бы нарушение старого кода. Авторы стандарта могут полагать, что предупреждений было достаточно, чтобы восполнить пробел для заинтересованных сторон.
Чтобы добавить некоторого прескриптивизма, я повторю утверждение @Lundin: «Никогда не используйте битовые поля для каких-либо целей». Если у вас есть веские причины, чтобы получить низкоуровневую и конкретную информацию о деталях макета памяти, которые заставят вас думать, что вам нужны битовые поля в первую очередь, другие связанные требования, которые у вас почти наверняка будут, столкнутся с их недостаточной спецификацией.
(TL; DR - Если вы достаточно опытны, чтобы законно "нуждаться" в битовых полях, они недостаточно четко определены, чтобы служить вам.)
источник
char
, подписи, определяемой реализацией , поддержки байтов, отличных от 8 бит и т. Д. И т. Д. Им не разрешалось ставить дебильные компьютеры в невыгодное положение на рынке.Это поведение, определяемое реализацией. Я делаю предположение, что машины, на которых вы запускаете это, используют целые числа со знаком, дополняющие два, и обрабатывают
int
в этом случае целое число со знаком, чтобы объяснить, почему вы не вводите if true часть оператора if.объявляется
enable
как 1-битовое битовое поле. Поскольку он подписан, допустимыми значениями являются-1
и0
. Настройка поля на1
переполнение этого бита, возвращающегося к-1
(это неопределенное поведение)По существу , когда имеет дело с подписанным битовым полем максимального значение ,
2^(bits - 1) - 1
которое является0
в данном случае.источник
-
и+
. Дополнение 2 не имеет значения.int
в этом случае все они считаются подписанными. Обидно, что битовые поля так недоопределены. В основном вот эта функция, проконсультируйтесь со своим компилятором, как ее использовать.Вы можете думать об этом как о том, что в системе дополнения до 2 крайний левый бит является битом знака. Таким образом, любое целое число со знаком с крайним левым битом является отрицательным значением.
Если у вас есть 1-битное целое число со знаком, оно имеет только знаковый бит. Таким образом, присвоение
1
этому единственному биту может установить только знаковый бит. Таким образом, при чтении его значение интерпретируется как отрицательное, поэтому оно равно -1.Значения 1 бит знаковое целое способна хранить
-2^(n-1)= -2^(1-1)= -2^0= -1
и2^n-1= 2^1-1=0
источник
В соответствии со стандартом C ++ n4713 предоставляется очень похожий фрагмент кода. Используемый тип -
BOOL
(пользовательский), но он может применяться к любому типу.На первый взгляд жирная часть кажется открытой для интерпретации. Однако правильное намерение становится ясным, когда
enum BOOL
объект является производным отint
.С приведенным выше кодом он дает предупреждение без
-Wall -pedantic
:Результат:
Если
enum BOOL : int
сделано простоenum BOOL
, то вывод будет таким, как указано в приведенном выше стандартном пассаже:Следовательно, можно сделать вывод, как и несколько других ответов, что этот
int
тип недостаточно велик для хранения значения «1» только в одном битовом поле.источник
Нет ничего плохого в вашем понимании битовых полей, которые я вижу. Я вижу, что вы сначала переопределили mystruct как struct mystruct {int enabled: 1; } а затем как struct mystruct s; . Вы должны были закодировать:
источник