Здравствуйте, k55, Вы писали:
k55>Подскажите где посмотреть вот про этот запрет (или объясните чем он обусловлен):
k55>error C2104 "'&' в битовом поле". k55> Была сделана попытка взять адрес битового поля.
Думаю, потому что минимально адресуемым является байт, а не бит...
Здравствуйте, valker, Вы писали:
V>Здравствуйте, k55, Вы писали:
k55>>Подскажите где посмотреть вот про этот запрет (или объясните чем он обусловлен):
k55>>error C2104 "'&' в битовом поле". k55>> Была сделана попытка взять адрес битового поля.
V>Думаю, потому что минимально адресуемым является байт, а не бит...
Даже если у меня структура вида:
union TPairByte {
struct {
byte m_FirstByte : 8;
byte m_SecondByte : 8;
};
short m_CommandShort;
};
Т.е. компилятор не парится с разбором?
Если есть желание — найдется 1000 возможностей.
Если нет желания — найдется 1000 причин.
Здравствуйте, k55, Вы писали:
k55>error C2104 "'&' в битовом поле". k55> Была сделана попытка взять адрес битового поля.
В стандарте, там где bitfields jписаны...
Общая идея такая, что когда ты используешь bitfields, например так:
struct MyBitFields {
int Data1 : 7;
int Data2 : 12;
int Data3 : 13;
};
То ты говоришь компилятору, что тебе не так важно быстро и удобно работать с этими данным, а важно, чтобы они занимали поменьше места.
Соответсвенно компилятор заведёт в вышеприведённом примере (это от реализации вообще-то зависит, но так в популярных тут компиляторах будет) ОДНО поле типа int и будет в нём всякими операциями с битами доставать и устанавливать куски.
То есть он, реально родит что-то вроде такого класса (это не реальный код, а просто изложение идеии на языке С++. С формальной точкип зрения тут есть много тонкостей, учёт которых загромоздит объяснение):
class MyBitFieldsImpl {
public:
void SetData1( int value ) { setField( Data1_mask, Data1_offset, value ); }
int GetData1() const { return getField( Data1_mask, Data1_offset ); }
void SetData2( int value ) { setField( Data2_mask, Data2_offset, value ); }
int GetData2() const { return getField( Data2_mask, Data2_offset ); }
void SetData3( int value ) { setField( Data3_mask, Data3_offset, value ); }
int GetData3() const { return getField( Data3_mask, Data3_offset ); }
private:
enum { Data1_offset = 0, Data1_mask = 127 };
enum { Data2_offset = 7, Data2_mask = (1 << 20) - 1 - Data1_mask };
enum { Data3_offset = 19, Data3_mask = 0xFFFFFFFF - Data2_mask };
int data;
void setField( int mask, int offset, int value )
{
data = ( data & ~mask ) | ( mask & ( value << offset ) );
}
int getField( int mask, int offset ) const
{
return ( data >> offset ) & mask;
}
}
В результате ты получаешь более компактные данные, но платишь за это менее эффективной работой с ними. Кроме того у тебя возникает ряд ограничений, одно из которых -- отсутсвие адреса у bitfield.
B действительно, просто в памяти компьютера физически нет такого int, в котором хранится поле MyFields::Data2, например. Так что и адреса у него нет.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
А смысл?
k55>Т.е. компилятор не парится с разбором?
А никто не обещал, что он по граница байт будет на всех платформах ранить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
От устройства идет команда в два байта, а точнее шорт.
Программа парсит эту команду и в соотвествии с протоколом выдает другому устройству нечто другое.
Так вот, чтобы распарсить нужно обращаться к каждому байту.
Ну и в ответ первому устройству нужно состовную команду из байтов высылать.
Посчитал что так удобнее будет.
Если есть желание — найдется 1000 возможностей.
Если нет желания — найдется 1000 причин.
Здравствуйте, k55, Вы писали:
k55>Ну и в ответ первому устройству нужно состовную команду из байтов высылать. k55>Посчитал что так удобнее будет.
Ну у тебя же и так там объединение из структуры из двух байт и одного двубайта?
Зачем туда ещё и bitfields прихреначивать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, k55, Вы писали:
k55>От устройства идет команда в два байта, а точнее шорт. k55>Программа парсит эту команду и в соотвествии с протоколом выдает другому устройству нечто другое. k55>Так вот, чтобы распарсить нужно обращаться к каждому байту.
Здравствуйте, Erop, Вы писали: E>Ну у тебя же и так там объединение из структуры из двух байт и одного двубайта? E>Зачем туда ещё и bitfields прихреначивать?
Мля.
Горе от ума.
Спасибо.
Если есть желание — найдется 1000 возможностей.
Если нет желания — найдется 1000 причин.
Здравствуйте, Erop, Вы писали:
k55>>error C2104 "'&' в битовом поле". k55>> Была сделана попытка взять адрес битового поля.
E>В стандарте, там где bitfields jписаны...
E>Общая идея такая, что когда ты используешь bitfields, например так:
struct MyBitFields {
E> int Data1 : 7;
E> int Data2 : 12;
E> int Data3 : 13;
E>};
E>То ты говоришь компилятору, что тебе не так важно быстро и удобно работать с этими данным, а важно, чтобы они занимали поменьше места.
Битовые поля — вообще чудаческие вещи.
Например, struct Test { signed int x : 1; }. Какие значения может принимать Test::x? Правильно, 0 и -1. test.x = 1 — переполнение.
Всё даже еще хуже. struct Test { int x : 1; } test = { 1 } может быть и well-formed. Потому что во всех остальных местах int = signed int, но только не в битовых полях! Там это просто не определено (9.6/3), так что int без указания знаковости может быть и unsigned.
Вообще,
1. Битовые поля — зло;
2. Битовые поля с членами знаковых типов — абсолютное зло. :-)
Здравствуйте, Roman Odaisky, Вы писали:
RO>2. Битовые поля с членами знаковых типов — абсолютное зло.
ИМХО Гитлер всё-таки был хуже
Но в целом я согласен, что bitfields лучше избегать. Просто потому, что так проще.
Есть ещё один забабах -- это когда ты так как-то пишешь:
enum MyEnum { zero, one, two, three };
struct MyStruct { MyEnum Data : 2; };
MyStruct tmp = { two };
То фиг его знаешь чего там получишь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Roman Odaisky, Вы писали:
RO>Всё даже еще хуже. struct Test { int x : 1; } test = { 1 } может быть и well-formed.
Не придирки ради, но только точности для. Well-formed оно-то в любом случае будет (ну, про точку с запятой все понятно, да). Вот значение и в самом деле может быть implementation-defined.
Здравствуйте, Roman Odaisky, Вы писали:
Pzz>>P.S. А вот адрес inline функции брать можно — такой у нас уродский язык RO>За что так сразу. inline — это стандартный аналог того, что MS называет __declspec(selectany), и это очень важно.
Вообще говоря, нет. __declspec(any) применяется к переменным, inline к ним неприменим.
Здравствуйте, Roman Odaisky, Вы писали:
Pzz>>P.S. А вот адрес inline функции брать можно — такой у нас уродский язык
RO>За что так сразу. inline — это стандартный аналог того, что MS называет __declspec(selectany), и это очень важно.
Я не знаю, чего мелкософт называет этим страшным словом. Но inline — это намек компилятору о том, что функцию хорошо бы поинлаинить. А register — намек компилятору о том, что переменную хорошо бы положить в регистр. Очевидно, что если функцию удалось поинлайнить, и переменную удалось положить в регистр, у них нет адреса. При этом адрес инлайновой функции получить можно (компилятору, естественно, придется ради этого сгенерировать нормальную, не инлайновую функцию), а адрес регистровой переменной получить нельзя. Получается неконсистентность.
Здравствуйте, Pzz, Вы писали:
Pzz>Но inline — это намек компилятору о том, что функцию хорошо бы поинлаинить.
В действительности современные компиляторы пробуют использовать все доступные в точке вызова определения функций. И inline и не inline. Но ключевое слово inline позволяет опубликовать определение функции для нескольких едениц трансляции, не нарушая ODR.
При этом указатель на inline функцию ничем не хуже указателя на не-inline функцию.
Ты же не можешь с указателем на функцию сдлеать ничего, кроме как сравнить два, или вызывать ненулевой. К тому подставился код функции в каком-то другом месте или нет это не имеет никакого отношения...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>В действительности современные компиляторы пробуют использовать все доступные в точке вызова определения функций. И inline и не inline. Но ключевое слово inline позволяет опубликовать определение функции для нескольких едениц трансляции, не нарушая ODR.
"Использовать" это оговорка? Имелось ввиду, инлайнить?
Современные компиляторы хоть и умеют автоматически инлайнить, обычно они все же воспринимают намеки. Скажем, явное описание inline может привести к тому, что поинлайнится функция, которую иначе бы компилятор инлайнить не стал.
E>При этом указатель на inline функцию ничем не хуже указателя на не-inline функцию. E>Ты же не можешь с указателем на функцию сдлеать ничего, кроме как сравнить два, или вызывать ненулевой. К тому подставился код функции в каком-то другом месте или нет это не имеет никакого отношения...
Это все не так просто, на самом деле. Например, если описать функцию в ашнике, и использовать этот ашник из нескольких разных модулей, указатель на функцию будет один и тот же. Статические переменные инлайновой функции будут одни и те же. Это требует довольно нетривиальной поддержки в линкере.
Здравствуйте, Pzz, Вы писали:
Pzz>"Использовать" это оговорка? Имелось ввиду, инлайнить?
А что обозначает слово "инлийнить"? Вообще-то компилятор не обязан именно подставлять. Он просто может использовать для оптимизации определение функции. Есть много путей это сделать вообще-то.
Pzz>Современные компиляторы хоть и умеют автоматически инлайнить, обычно они все же воспринимают намеки. Скажем, явное описание inline может привести к тому, что поинлайнится функция, которую иначе бы компилятор инлайнить не стал.
Ну обычно у них есть ещё всякие другие слова для намёков. А вот собственно inline примерно так же учитывают, как register...
Pzz>Это все не так просто, на самом деле. Например, если описать функцию в ашнике, и использовать этот ашник из нескольких разных модулей, указатель на функцию будет один и тот же. Статические переменные инлайновой функции будут одни и те же. Это требует довольно нетривиальной поддержки в линкере.
Во-первых это таки проблемы линкера, но они невелики
Во-вторых что тут умного? Ну заводишь сегмент данных который называется "статическая переменная из такой-то функции" и всюду ссылаешься на него.
Ну и ставишь на этот символ флаг, чтобы линкер не ругался на наружение ODR, а взял любое из определений.
Ну и на само тело функции тоже.
И что за проблема?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском