Распределение записей с битовыми полями в C # - PullRequest
3 голосов
/ 16 февраля 2012

Можно ли маршалировать структуру в стиле C, содержащую битовые поля, в структуру C #, или вам придется маршировать ее в базовый тип, а затем делать битовые маски?

Например, я бы хотелвыполнить маршалирование из структуры стиля C следующим образом:

struct rgb16 {
    unsigned int R : 4;
    unsigned int G : 5;
    unsigned int B : 4;
}

и выполнить маршализацию чего-то вроде этого:

[StructLayout(LayoutKind.Sequential)]
public struct Rgb16 {
    public byte R;
    public byte G;
    public byte B;
}

Ответы [ 4 ]

6 голосов
/ 16 февраля 2012

В C # нет битовых полей. Так что я бы пошел со свойствами, которые инкапсулируют битовую скрипку:

[StructLayout(LayoutKind.Sequential)]
public struct Rgb16 {
    private readonly UInt16 raw;
    public byte R{get{return (byte)((raw>>0)&0x1F);}}
    public byte G{get{return (byte)((raw>>5)&0x3F);}}
    public byte B{get{return (byte)((raw>>11)&0x1F);}}

    public Rgb16(byte r, byte g, byte b)
    {
      Contract.Requires(r<0x20);
      Contract.Requires(g<0x40);
      Contract.Requires(b<0x20);
      raw=r|g<<5|b<<11;
    }
}

Я избегал добавления сеттеров, потому что мне нравятся неизменяемые структуры, но в принципе вы тоже можете их добавлять.

3 голосов
/ 19 февраля 2014

Это мой "безопасный c #" порт структуры rgb16.

[StructLayout(LayoutKind.Explicit, Size = 2, Pack = 1)]
public class Color16
{
    // Btifield: 5
    [FieldOffset(0)]
    private ushort b_i;

    public ushort b
    {
        get { return (ushort)((b_i >> 11) & 0x1F); }
        set { b_i = (ushort)((b_i & ~(0x1F << 11)) | (value & 0x3F) << 11); }
    }

    // Bitfield: 6
    [FieldOffset(0)]
    private ushort g_i;

    public ushort g
    {
        get { return (ushort)((g_i >> 5) & 0x7F); }
        set { g_i = (ushort)((g_i & ~(0x7F << 5)) | (value & 0x7F) << 5); }
    }

    // Bitfield: 5
    [FieldOffset(0)]
    private ushort r_i;

    public ushort r
    {
        get { return (ushort) (r_i & 0x1F); }
        set { r_i = (ushort) ((r_i & ~0x1F) | (value & 0x1F)); }
    }

    [FieldOffset(0)]
    public ushort u;

    public Color16() { }
    public Color16(Color16 c) { u = c.u; }
    public Color16(ushort U) { u = U; }

}
0 голосов
/ 24 ноября 2018

Я потратил большую часть вчерашнего дня, пытаясь решить эту проблему как большую часть проблемы «Представления битовых полей объединения с использованием StrucLayout и FieldOffset в c #», которая не только ответит на ваш вопрос (см. Выше), но может быть найдена здесь. :

Представление битовых полей объединения с использованием StrucLayout и FieldOffset в c #

По сути, вам нужно определить структуру (тип значения) и использовать объект BitVector32 , чтобы определить секцию битового поля для каждого битового поля, которое вы хотите представить. Вы можете пропустить часть о союзе, поскольку это не относится к вашему вопросу, но большая часть поста по-прежнему относится к вашему вопросу.

Просто для удовольствия, я подумал, что я бы подстроил структуру C # для вашего примера RGB16:

Примечание. Объект BitVector32 имеет длину 32 бита, поэтому значение 16 в прозвище вводит в заблуждение ... обратите внимание на это

[StructLayout(LayoutKind.Explicit, Size = 1, CharSet = CharSet.Ansi)]
public struct Rgb16
{
    #region Lifetime

    /// <summary>
    /// Ctor
    /// </summary>
    /// <param name="foo"></param>
    public Rgb16(int foo)
    {
        // allocate the bitfield
        buffer = new BitVector32(0);

        // initialize bitfield sections
        r = BitVector32.CreateSection(0x0f);        // 4
        g = BitVector32.CreateSection(0x1f, r);     // 5
        b = BitVector32.CreateSection(0x0f, g);     // 4
    }

    #endregion

    #region Bifield

    // Creates and initializes a BitVector32.
    [FieldOffset(0)]
    private BitVector32 buffer;

    #endregion

    #region Bitfield sections

    /// <summary>
    /// Section - Red
    /// </summary>
    private static BitVector32.Section r;

    /// <summary>
    /// Section - Green
    /// </summary>
    private static BitVector32.Section g;

    /// <summary>
    /// Section - Blue
    /// </summary>
    private static BitVector32.Section b;

    #endregion

    #region Properties

    /// <summary>
    /// Flag 1
    /// </summary>
    public byte R
    {
        get { return (byte)buffer[r]; }
        set { buffer[r] = value; }
    }

    /// <summary>
    /// Flag 2
    /// </summary>
    public byte G
    {
        get { return (byte)buffer[g]; }
        set { buffer[g] = value; }
    }

    /// <summary>
    /// Flag 1
    /// </summary>
    public byte B
    {
        get { return (byte)buffer[b]; }
        set { buffer[b] = value; }
    }

    #endregion

    #region ToString

    /// <summary>
    /// Allows us to represent this in human readable form
    /// </summary>
    /// <returns></returns>
    public override string ToString()
    {
        return $"Name: {nameof(Rgb16)}{Environment.NewLine}Red: {R}: Green: {G} Blue: {B}  {Environment.NewLine}BitVector32: {buffer}{Environment.NewLine}";
    }

    #endregion
}

Чтобы использовать это, вы должны выделить следующее:

internal static class Program
{
    /// <summary>
    /// Main entry point
    /// </summary>
    /// <param name="args"></param>
    static void Main(string[] args)
    {

        var rgb16 = new Rgb16(0)
        {
            R = 24,
            G = 16,
            B = 42
        };

Также, пожалуйста, обратите внимание, что есть ссылка на это:

Битовые поля в C #

Здесь есть много других ответов, но у них есть много подводных камней, о которых нужно знать. Пожалуй, лучшее, что я могу сделать здесь, это просто перечислить то, что вы можете искать:

  1. Обязательно упакуйте свои данные на границе байтов
  2. Обязательно укажите размер типов данных, т. Е. int изменяет размер в зависимости от аппаратного обеспечения, System.Int32 не изменяет.
  3. Убедитесь, что вы соблюдаете порядковый номер ваших целочисленных типов данных
  4. Избегайте, если это вообще возможно, каких-либо связей с базовым языком, то есть избегайте менеджера языковой памяти - придерживайтесь "простых старых типов данных". Это значительно упростит маршалинг данных по сети.
0 голосов
/ 16 февраля 2012

Я упорядочил битовые поля, такие как:

public struct Rgb16 {
    public ushort Value; // two byte value that internally contain structure R(4):G(5):B(4)

    public Rgb16BitField GetBitField
    {
        get; set;
    }
}

, где свойство создает новую структуру, как вы упомянули, путем деления значения на биты.

Это не лучший способ сделать это, но я не нашел ничего другого, что сработало бы для меня. Я могу предоставить код для GetBitField, если хотите (он не очень компактный)

Upd: Ссылка, предоставленная Тони в комментариях к вашему вопросу, использует ту же идею, но кажется более точной, чем моя, поэтому используйте его решение, если вы не можете найти ничего лучше

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...