2010-02-11 2 views
3

Скажем, у меня есть значение ushort, которое я хотел бы установить биты от 1 до 4 включительно (при условии, что 0 - это LSB, а 15 - MSB).Set Range Bits в ushort

В C++ можно определить структуру, которая отображенный конкретные биты:

struct KibblesNBits 
{ 
    unsigned short int TheStart: 1; 
    unsigned short int TheMeat: 4; 
    unsigned short int TheRest: 11; 
} 

Затем можно присвоить значение «TheMeat» непосредственно. Я хочу сделать что-то подобное на C#. В идеале я хотел бы определение несильно, который выглядел так:

public ModValue SetRange<ModValue, RangeValue>(ModValue valueToMod, int startIndex, int endIndex, RangeValue rangeValueToAssign) 

Это также должно было бы Валиде, что rangeValueToAssign не превышает максимального размера (предполагающие значения без знака от 0 до макс). Поэтому, если диапазон от 1 до 4, это 4 бита, диапазон будет от 0 до 15. Если он выходит за эти пределы, выкиньте исключение.

Я ничего не нашел в классе BitConverter, который мог бы сделать что-то вроде этого. Лучше всего я мог подумать о том, чтобы использовать мануальные сдвиговые операторы. Есть лучший способ сделать это?

Изменить: не общая версия может выглядеть примерно так:

public static ushort SetRange(ushort valueToMod, int startIndex, int endIndex, ushort rangeValueToAssign) 
    { 
    // Determine max value 
    ushort max_value = Convert.ToUInt16(Math.Pow(2.0, (endIndex - startIndex) + 1.0) - 1); 
    if(rangeValueToAssign > max_value) throw new Exception("Value To Large For Range"); 
    // Shift the value and add it to the orignal (effect of setting range?) 
    ushort value_to_add = (ushort)(rangeValueToAssign << startIndex); 
    return (ushort)(valueToMod + value_to_add); 
    } 

Где:

ushort new_val = SetRange(120, 1, 2, 3); 

приведет к 'new_val' быть установлен в 126.

+1

Что не так с операторами сдвига? они обеспечили бы лучшую производительность здесь ... – TJMonk15

+0

@ TJMonk15 - Я думаю, с ними ничего не случилось, просто искали универсальное решение или посмотрели, есть ли другой способ сделать это, что я просто отсутствую – SwDevMan81

+0

Прошу опубликовать фрагмент код, иллюстрирующий, как вы хотели бы использовать это устройство. Я все еще немного неясен относительно того, что вы хотите сделать SetRange, в точности. –

ответ

0

Если вы хотите этот тип доступа, рассмотрите BitVector32 или BitArray, или ознакомьтесь с побитовой арифметикой. Вы можете сделать явное расположение структур на C# (вызывая объединение), но я не думаю, что это в ваших интересах. Это в первую очередь предназначено для сценариев взаимодействия.

Для получения информации, то битовые операторы работают в основном на uint/int/ulong/long - не столько меньшие целочисленные типы.

+0

@Marc - Спасибо, знаете ли вы, если у кого-то из них есть функция SetRange, которую я ищу. Я тоже ничего не вижу на страницах msdn. – SwDevMan81

+0

@ SwDevMan81 - нет, но вы могли бы написать метод расширения для них достаточно легко? –

0

Я не знаю ни одной языковой функции (кроме ручного смещения бит), которая бы достигла этого.

Единственное, что приходит мне на ум - это старый BitArray из .NET 1.1. Но вы можете манипулировать только отдельными битами, а не битами.

Итак, нет.

-1

Вот исправление для обновления:

public static ushort SetRange(ushort valueToMod, int startIndex, int endIndex, ushort rangeValueToAssign) 
    { 
    // Determine max value 
    ushort max_value = Convert.ToUInt16(Math.Pow(2.0, (endIndex - startIndex) + 1.0) - 1); 
    if(rangeValueToAssign > max_value) throw new Exception("Value To Large For Range"); 
    // Clear our bits where we want to "Set" the value for 
    for(int i=startIndex; i<endIndex; i++) 
     valueToMod &= ~(1<<i); 
    // Shift the value and add it to the orignal (effect of setting range?) 
    ushort value_to_add = (ushort)(rangeValueToAssign << startIndex); 
    return (ushort)(valueToMod + value_to_add); 
    } 
+0

Ницца, ок теперь просто сделай это родовым, и я продаюсь – SwDevMan81

+0

Ghhh! Math.pow? Гадкий! Вместо этого используйте побитовый сдвиг (например, в вашем цикле for). – vladr

+2

Умм, это был его код .... – TJMonk15

2
public static int SetRange(int num, int from, int to, int value) 
{ 
    if (from < 0 || from > to || to >= 32) throw new ArgumentException("from/to are not valid"); 
    if (value >= (2 << (to - from)) && (to - from < 31)) throw new ArgumentException("value is too large"); 
    return num & ~(((2 << to) - 1) - ((1 << from) - 1)) | (value << from); 
} 

Нет для петель или Math.pow (что удивительно медленно, путь медленнее, чем Sin/Cos и т.д.).

Что касается общего - извините, но это не сработает. Нет базового типа для чисел в C# (или .NET), поэтому это просто невозможно. Похоже, вы пытаетесь использовать дженерики, такие как функции шаблонов на C++, - не обманывайте себя похожими взглядами; они совершенно разные.

Если у вас должны быть разные типы, я бы предложил перегрузки.

public static int SetRange(int num, int from, int to, int value) 
{ 
    if (from < 0 || from > to || to >= 32) throw new ArgumentException("from/to are not valid"); 
    if (value >= (2 << (to - from)) && (to - from < 31)) throw new ArgumentException("value is too large"); 
    return num & ~(((2 << to) - 1) - ((1 << from) - 1)) | (value << from); 
} 

public static ushort SetRange(ushort num, int from, int to, ushort value) 
{ 
    if (from < 0 || from > to || to >= 16) throw new ArgumentException("from/to are not valid"); 
    if (value >= (2 << (to - from))) throw new ArgumentException("value is too large"); 
    return (ushort) (num & ~(((2 << to) - 1) - ((1 << from) - 1)) | (value << from)); 
} 

Однако, в C# это может быть более идиоматическим просто всегда использовать Int (или длинными, если вам это нужно).

Смежные вопросы