Каковы варианты использования IsLittleEndian в классе BitConverter? - PullRequest
8 голосов
/ 20 июня 2011

Я был так счастлив, когда обнаружил IsLittleEndian поле в BitConverter.Я думал, конечно, что это должно быть там, и я должен быть в состоянии указать любой порядок байтов, который мне нравится.Ну, мое счастье длилось недолго.Потратил некоторое время, пока не узнал, что нет возможности установить поле.Поле имеет значение readonly, и оно установлено в true только в статическом конструкторе:

static BitConverter()
{
    IsLittleEndian = true;
}

Забавно, что поле фактически используется в коде.Например, реализация метода ToInt32 выглядит следующим образом:

if (IsLittleEndian)
{
     return (((numRef[0] | (numRef[1] << 8)) | (numRef[2] << 0x10)) | (numRef[3] << 0x18));
}
return ((((numRef[0] << 0x18) | (numRef[1] << 0x10)) | (numRef[2] << 8)) | numRef[3]);

Похоже, что ToInt32 вполне способен обрабатывать как маленькие, так и большие порядковые номера.

Мой вопрос: как получилосьесть очень полезный кусок кода, который уже реализован и находится там в FCL, но нет никакого способа его использовать (если, конечно, вы не начнете возиться с отражением)?Это просто потому, что некоторые разработчики не уложились в срок и оставили работу наполовину?Даже если так, почему код недоступен, а поле есть?Я надеюсь, что для этого есть веская причина.

Я хочу прояснить ситуацию.Мне не нужно решение о том, как обрабатывать значения с прямым порядком байтов.У меня есть решение.Решение на самом деле показано в моем вопросе.

Ответы [ 7 ]

5 голосов
/ 20 июня 2011

К сожалению, поле IsLittleEndian просто информирует вас.Но у библиотеки Jon Skeets MiscUtil есть хороший EndianBitConverter, который поддерживает маленький и большой порядок байтов.Существуют также классы BinaryWriter / -Reader с поддержкой порядка байтов.

Вот ссылка: http://www.yoda.arachsys.com/csharp/miscutil/

Редактировать: извините, но у меня нет лучшего объяснения.Я думаю, что это должно было быть включено во фреймворк, и я думаю, что код в настоящее время там, так что легко перенести Конвертер на другую архитектуру.сделать поле публичным.Преобразователь статичен, поэтому изменение флага эффективно меняет глобальное состояние, и в многопоточном сценарии это будет иметь катастрофические последствия.Возможно, вам нужно предоставить два объекта BitConverter, которые вы можете создавать и использовать локально (именно это делает MiscUtil).Это требует дополнительных классов и / или интерфейсов, так что, возможно, это был крайний срок, и на данный момент его просто отбросили.Будем надеяться, что это будет добавлено через некоторое время.

3 голосов
/ 30 июня 2011

Сначала давайте установим, что класс BitConverter специально предназначен для преобразования бит только для локального процессора .Вот почему IsLittleEndian только для чтения.В результате он не поддерживает преобразование в или из старшего порядкового номера, если локальный процессор имеет младший порядок и наоборот.

Хотя я не знаю причин для исключения поддержки общего порядка байтов, наиболее логичнымпричина для меня производительность .Класс, который широко используется во всем фреймворке по своему прямому назначению (преобразование в непосредственный порядок и из собственного процессора), должен быть как можно более быстродействующим.Ограничивая общность класса, его производительность улучшается за счет ограничения случаев, которые должны быть обработаны.Поддерживая только little-endian, он, вероятно, измерим быстрее .

ОК, так что теперь мы переходим к сути вопроса.Зачем авторам включать код для работы как с прямым порядком байтов, так и с прямым порядком байтов, если общий дизайн класса намеревается поддерживать только один?

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

  • дизассемблированный код, который ссылается на IsLittleEndian , является неважным с точки зрения производительности
  • написанием переносимого кода,если это не влияет на производительность, это хорошая программная инженерия

Причина, по которой код, скопированный из метода ToInt32, не важен, потому что он толькоиспользуется для памяти без выравнивания .Путь кода 99% является прямым небезопасным "memcpy" битов.

Даже в том случае, если происходит преобразование из невыровненной памяти, код, обрабатывающий его, на порядок менее эффективен, чем необработанныйметод.Таким образом, дополнительное условие не влияет на производительность.

Чистый результат:

  • Класс BitConverter максимально эффективен для его ограниченногопредназначение
  • Исходный код для BitConverter, тем не менее, переносим на архитектуры процессоров с прямым порядком байтов
2 голосов
/ 23 июля 2014

Ответ заключается в поиске справочного источника для класса BitConverter.

Соответствующий экстракт:

        // This field indicates the "endianess" of the architecture.
        // The value is set to true if the architecture is
        // little endian; false if it is big endian.
#if BIGENDIAN
        public static readonly bool IsLittleEndian /* = false */;
#else
        public static readonly bool IsLittleEndian = true;
#endif

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

1 голос
/ 20 июня 2011

Согласно документации MSDN IsLittleEndian просто информировать вас (вашу программу или класс BitConverter) о том, является ли архитектура Little или Big Endian.Я не думаю, что за пределами этого есть предполагаемое использование.

0 голосов
/ 20 июня 2011

Я почти уверен, что они установили его на true без возможности false, потому что все версии Windows имеют младший порядок .

Теперь, вопрос о том, чтобы они выполняли if (IsLittleEndian) в классе, который никогда не устанавливает IsLittleEndian на что-либо, кроме true, скорее всего, является сценарием на всякий случай. Таким образом, если когда-либо потребуется компиляция .NET BCL для big-endian, будет достаточно простого #if / #else вокруг этого одного назначения, вместо того, чтобы писать новый код.

Бьюсь об заклад, Mono устанавливает его false для некоторых операционных систем и архитектур.

Редактировать : И я был прав. Mono делает следующее . Технически ни один другой код не нуждался бы в дополнениях, за исключением того, что им пришлось писать все по-другому в Mono из-за проблем с авторским правом.

public static readonly bool IsLittleEndian = AmILittleEndian ();

static unsafe bool AmILittleEndian ()
{
  // binary representations of 1.0:
  // big endian: 3f f0 00 00 00 00 00 00
  // little endian: 00 00 00 00 00 00 f0 3f
  // arm fpa little endian: 00 00 f0 3f 00 00 00 00
  double d = 1.0;
  byte *b = (byte*)&d;
  return (b [0] == 0);
}
0 голосов
/ 20 июня 2011

См. http://snipplr.com/view/15179/adapt-systembitconverter-to-handle-big-endian-network-byte-ordering-in-order-to-create-number-types-from-bytes-and-viceversa/, если вы хотите реализацию, которая позволяет вам устанавливать порядковый номер.

0 голосов
/ 20 июня 2011

устанавливается внутренне в зависимости от типа архитектуры.

из документов :

"Различные компьютерные архитектуры хранят данные с использованием разных порядков байтов." Big-endian "означает, что самый старший байт находится в левом конце слова. «Little-endian» означает, что самый старший байт находится в правом конце слова. "

Редактировать:

Это было дизайнерское решение, принятое командой c #.Функция способна конвертировать из обоих типов, потому что она может использоваться в обоих типах систем.разработчик должен преобразовать его в противном случае.

"... Все методы BitConverter принимают или возвращают байтовые массивы в порядке байтов SYSTEM ..."

int i = BitConverter.ToInt32(byte[] inputdata);
(manipulate i)
return BitConverter.GetBytes(i);

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

Для получения дополнительной информации прочитайте эту статью .

...