битовые маски для union

Тема в разделе "LANGS.C", создана пользователем Black_mirror, 7 дек 2011.

  1. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    Пусть у нас имеется некоторый union вида
    Код (Text):
    1. union flags{
    2.   long all;
    3.   struct{
    4.     long flag0:1;
    5.     long flag1:1;
    6.     ...
    7.     long flag30:1;
    8.     long flag31:1;
    9.   };
    10. };
    который мы хотим передавать в некоторую функцию. Вопрос собственно в том, как установить в нём интересные нам флаги при вызове функции, без объявления перед ним union'а с несколькими операторами присваивания? Или как объявить для этих флагов битовые маски независимым от порядка байт образом?
     
  2. T800

    T800 Member

    Публикаций:
    0
    Регистрация:
    7 дек 2006
    Сообщения:
    293
    Адрес:
    Moscow
    Black_mirror
    А как вы обычно передаёте в функции массивы? Думаю что вы сначала определяете массив, наполняете его (поэлементно) и после передаёте в функцию указатель на этот массив.
    Тут логика почти такая же.
    А коли хотите всё сразу, то юзаёте long all.
     
  3. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    T800
    Мне просто сначала показалось, что
    #define FLAGn (1L<<n)
    может дать не ту маску, но сейчас склоняюсь к выводу что маска должна получиться правильная.
     
  4. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    У Кернигана и Ричи вроде чего-то было насчёт того, как битовые поля структуры отображаются на байты - что раньше объявлено, то становится более младшими битами.
     
  5. kam1

    kam1 New Member

    Публикаций:
    0
    Регистрация:
    26 июн 2011
    Сообщения:
    10
    М.б использовать сделать конструктор параметризованный у union и использовать анонимные экземпляры при вызове функций?
    напр, как-нибудь так:

    Код (Text):
    1. #include <iostream>
    2. #include <cstdio>
    3.  
    4. using namespace std;
    5.  
    6. union flags{
    7.   long all;
    8.   struct{
    9.     long flag0:1;
    10.     long flag1:1;
    11.     //...
    12.     long flag30:1;
    13.     long flag31:1;
    14.   };
    15.   flags(bool b1, bool b2):flag0(b1),flag1(b2){};
    16. };
    17.  
    18. void somefunc(flags un1);
    19.  
    20. int main()
    21. {
    22.  somefunc(flags(1,0));            
    23.  
    24.  return 0;
    25. }
    26.  
    27. void somefunc(flags un1){
    28.  printf("flag0: %s\n", (un1.flag0)?"true\n":"false\n" );
    29.  printf("flag1: %s\n", (un1.flag1)?"true\n":"false\n" );
    30. };
     
  6. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    CyberManiac
    По идее, если написано long field:n, то сначала процессор должен прочитать long в котором это поле находится, а потом наложить маску/сдвинуть, чтобы достать это поле. Или не сдвигать, а объединить со сдвинутым новым значением поля и записать обратно. Делать иначе на мой взгляд будет более накладно.
     
  7. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    Black_mirror
    "long" тут просто идентификатор типа, аналогичный signed int, длина в битах всегда используется та, что после ":". Уж не знаю, зачем КиР эту хрень замутили - видимо, чтобы битовые поля могли быть signed и unsigned. Но знаковое поле из одного бита, после некоторого размышления, представляется как полный ахтунг, ибо должно принимать значения 0 и -1, а не то, что обычно думают.
     
  8. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    CyberManiac
    То есть вы хотите сказать, что если в union из первого сообщения установить к примеру flag7 и flag8, а затем прочитать их через all, то нет гарантий, что они окажутся рядом?
     
  9. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Black_mirror
    То, что они окажутся рядом, гарантируется стандартом. Не гарантируется порядок их следования.
    Часто можно увидеть, что компилируется считывание, например, соответствующего байта, если битовое поле не пересекает байтовую границу.
     
  10. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    l_inc
    Не гарантируется в том смысле, что компилятор может их как со старших, так и с младших разрядов начинать размещать? То есть объявление соответствующих масок будет зависеть от компилятора?
     
  11. CyberManiac

    CyberManiac New Member

    Публикаций:
    0
    Регистрация:
    2 сен 2003
    Сообщения:
    2.473
    Адрес:
    Russia
    Black_mirror
    Почему? Очень даже окажутся. all накладывается на структуру.

    Согласно КиР первое из битовых полей (flag0) окажется самым младшим битом all. Как это будет выглядеть на big-endian, правда, не в курсе, но в мэйнстрим-программах этих мутантов можно вообще в расчёт не брать.
     
  12. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Black_mirror
    Не сталкивался с компиляторами, где ранее объявленное поле не попадает в младшие биты (даже писал кроссархитектурный код, работоспособность которого от этого зависела), но согласно стандарту да:

    (первое подчеркнул, т.к. тоже довольно важный момент)
     
  13. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    l_inc
    Из первой фразы я делаю вывод что компилятор действительно может выделять место хоть побайтово, и на big-endian установив flag7 и flag8, а затем прочитав их как long мы можем получить 0x80010000. Похоже, что самый переносимый способ объявить битовые маски это сделать 32 константных union и использовать их. Или вообще отказаться от union в пользу обычного long.
     
  14. l_inc

    l_inc New Member

    Публикаций:
    0
    Регистрация:
    29 сен 2005
    Сообщения:
    2.566
    Black_mirror
    Эм... Да... Верно. Я её интерпретировал немного не так, но, похоже, Вы правы. Да и на little-endian теоретически можно получить 0x00008001, если ранее объявленное битовое поле будет попадать в старшие биты ячейки (т.е. flag7 на самом деле будет младшим битом байта, flag8 старшим битом следующего байта).
     
  15. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Black_mirror
    Может, но только с учетом 2го и 3го предложений. Если все битовые поля объявлены одинакового макс.размера (например, unsigned long), то условие 2-го предложения выполняется для всех бит и соотв-но они должны идти подряд друг за другом без разрывов (по крайней мере для LE, а для BE - хз). А 3-е предложение по сути означает выравнивание для полей разного размера, и хотя по стандарту оно implementation-defined, тем не менее "нормальные" компиляторы по идее должны придерживаться неких общих правил как и с выравниванием полей обычных структур
    PS: В мсдн где-то есть заметка о правилах выравнивании битовых полей с примерами