Почему BitConverter.ToInt32 считывает по одному байту за раз, если данные не выровнены по заданному смещению?

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

При просмотре исходного кода BitConverter недавно я наткнулся на странный фрагмент кода:

public static unsafe int ToInt32(byte[] value, int startIndex)
{
    fixed (byte* pbyte = &value[startIndex])
    {
        if (startIndex % 4 == 0) // data is aligned 
            return *((int*)pbyte);
        else
        { 
            if (IsLittleEndian)
            {  
                return (*pbyte) | (*(pbyte + 1) << 8)  | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24); 
            } 
            else
            { 
                return (*pbyte << 24) | (*(pbyte + 1) << 16)  | (*(pbyte + 2) << 8) | (*(pbyte + 3));                         
            } 
        }
    }
}

Как приведение pbyte к int* (строка 6) может нарушить выравнивание данных в этом сценарии? Я оставил это для краткости, но в коде есть надлежащая проверка аргументов, поэтому я почти уверен, что это не может быть нарушением доступа к памяти. Теряет ли он точность при броске?

Другими словами, почему код нельзя упростить до:

public static unsafe int ToInt32(byte[] value, int startIndex)
{
    fixed (byte* pbyte = &value[startIndex])
    {
        return *(int*)pbyte;
    }
}

Изменить: Здесь находится рассматриваемый фрагмент кода.


person James Ko    schedule 26.08.2015    source источник
comment
Операции с данными, выровненными по границе размера данных, выполняются быстрее, а на некоторых процессорах доступ к невыровненным словам/двойным словам/плавающим/двойным числам является нарушением доступа... (прокомментируйте, поскольку у меня нет под рукой хорошей ссылки).   -  person Alexei Levenkov    schedule 26.08.2015
comment
@AlexeiLevenkov Тем не менее, вы создаете две дополнительные ветки, несколько побитовых операций, разыменование и pbyte + 1, pbyte + 2 и т. д. (3 из которых не будут выровнены) только для того, чтобы избежать этого невыравнивания. Мне кажется довольно излишним.   -  person James Ko    schedule 26.08.2015
comment
Не уверен в вашем комментарии - есть процессоры, к которым вы не можете получить доступ к невыровненным int - stackoverflow.com/questions/1237963/ - так какую альтернативную реализацию вы предлагаете по сравнению с побайтовым чтением?   -  person Alexei Levenkov    schedule 26.08.2015


Ответы (1)


Могу поспорить, что это связано с этой частью §18.4 в версии 5.0 спецификации С# (выделено мной):

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

Побайтовое копирование в случае «невыровненного» выполняется, чтобы не полагаться на явно неопределенное поведение.

person Joe Amenta    schedule 29.12.2015