Реверсивный порядок байтов в .NET

Что сработало для меня:

В активном httpd.conf найти

<IfModule mime_module>
...
</IfModule>

Отсутствует следующее

AddType application/x-httpd-php .php
AddHandler application/x-httpd-php .php

После перезапуска apache , .php правильно разбираются.

13
задан Peter Mortensen 5 September 2016 в 14:41
поделиться

4 ответа

BinaryReader.ReadInt64 по своей природе немного эндианский. Из документации:

BinaryReader читает этот тип данных в little-endian формате.

На самом деле, мы можем проверить источник для BinaryReader.ReadInt64 с помощью рефлектора.

public virtual long ReadInt64() {
    this.FillBuffer(8);
    uint num = (uint) (((this.m_buffer[0] |
              (this.m_buffer[1] << 0x08)) |
              (this.m_buffer[2] << 0x10)) |
              (this.m_buffer[3] << 0x18));
    uint num2 = (uint) (((this.m_buffer[4] |
               (this.m_buffer[5] << 0x08)) |
               (this.m_buffer[6] << 0x10)) |
               (this.m_buffer[7] << 0x18));
    return (long) ((num2 << 0x20) | num);
}

Показывая, что BinaryReader. ReadInt64 читается как little endian независимо от базовой машинной архитектуры.

Теперь, BitConverter.ToInt64 должен уважать endianness Вашей базовой машинной архитектуры. В рефлекторе мы видим

public static unsafe long ToInt64(byte[] value, int startIndex) {
    // argument checking elided
    fixed (byte* numRef = &(value[startIndex])) {
        if ((startIndex % 8) == 0) {
            return *(((long*) numRef));
        }
        if (IsLittleEndian) {
            int num = (numRef[0] << 0x00) |
                      (numRef[1] << 0x08) |
                      (numRef[2] << 0x10) |
                      (numRef[3] << 0x18);
            int num2 = (numRef[4] << 0x00) |
                       (numRef[5] << 0x08) |
                       (numRef[6] << 0x10) |
                       (numRef[7] << 0x18);
            return (((long) ((ulong) num)) | (num2 << 0x20));
        }
        int num3 = (numRef[0] << 0x18) |
                   (numRef[1] << 0x10) |
                   (numRef[2] << 0x08) |
                   (numRef[3] << 0x00);
        int num4 = (numRef[4] << 0x18) |
                   (numRef[5] << 0x10) |
                   (numRef[6] << 0x08) |
                   (numRef[7] << 0x00);
        return (((long) ((ulong) num4)) | (num3 << 0x20));
}

Так что, если startIndex совпадает с нулевым модулем восемь, то прямое приведение выполняется из восьми байт, начиная с адреса numRef. Этот случай обрабатывается специально из-за проблем с выравниванием. Строка кода

return *(((long *) numRef));

транслируется непосредственно в

    ldloc.0      ;pushes local 0 on stack, this is numRef
    conv.i       ;pop top of stack, convert to native int, push onto stack
    ldind.i8     ;pop address off stack, indirect load from address as long
    ret          ;return to caller, return value is top of stack

Так что мы видим, что в данном случае ключом является инструкция ldind.i8. CLI агностик насчет эндианности лежащей в основе машины. Он позволяет компилятору JIT справиться с этой проблемой. На машине little-endian ldind.i8 будет загружать более высокие адреса в более значащие биты, а на машине big-endian ldind.i8 будет загружать более высокие адреса в менее значащие байты. Поэтому в данном случае эндианность обрабатывается корректно.

В другом случае можно заметить, что существует явная проверка статического свойства BitConverter.IsLittleEndian. В случае little endian буфер интерпретируется как little endian (так что память { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 } интерпретируется как длинный 0x0706050403020100), а в случае большого эндиана буфер интерпретируется как большой эндиан (так что память { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 } интерпретируется как длинный 0x0001020304050607). Итак, для BitConverter все сводится к эндианности машины нижнего белья. Обращаю ваше внимание, что вы находитесь на чипе Intel в Windows 7 x64. Чипы Intel немного эндианские. Обращаю внимание, что в Reflector статический конструктор для BitConverter определен как:

static BitConverter() {
    IsLittleEndian = true;
}

Это на моей машине Windows Vista x64. (Он может отличаться, скажем, на .NET CF на XBox 360.) Нет причин для того, чтобы Windows 7 x64 отличалась. Следовательно, Вы уверены, что BitConverter.IsLittleEndian является false? Это должно быть true и поэтому поведение, которое Вы видите, является правильным.

.
22
ответ дан 1 December 2019 в 19:02
поделиться

Вы находитесь на little endian машине, на которой сначала хранятся наименее значимые байты целых чисел.

.
5
ответ дан 1 December 2019 в 19:02
поделиться

BinaryReader принимает малый Эндианский порядок: http://msdn.microsoft.com/en-us/library/system.io.binaryreader.readint64.aspx

4
ответ дан 1 December 2019 в 19:02
поделиться

Если вас волнует эндианность ваших байтов, Джон Скит (Jon Skeet) написал класс, позволяющий выбрать эндианский порядок при преобразовании.

Смотрите C# маленький эндиан или большой эндиан?

2
ответ дан 1 December 2019 в 19:02
поделиться
Другие вопросы по тегам:

Похожие вопросы: