Простая побитовая манипуляция для порядкового числа с прямым порядком байтов в машине с прямым порядком байтов? - PullRequest
4 голосов
/ 13 апреля 2011

Для конкретной необходимости я строю четырехбайтовое целое число из четырех однобайтовых символов, не используя ничего особенного (на моей платформе с прямым порядком байтов):

    return (( v1 << 24) | (v2 << 16) | (v3 << 8) | v4);

Я знаю, что целое число хранится вмашина с прямым порядком байтов выглядела бы как AB BC CD DE вместо DE CD BC AB с небольшим порядком байтов, хотя это полностью повлияло бы на мою работу, так как я буду перемещаться неправильно, или это просто вызвало бы правильный результат, который сохраняется в обратном порядке и нуждается вбыть перевернутым?

Мне было интересно, создать ли вторую версию этой функции для выполнения (пока неизвестных) операций с битами для машины с прямым порядком байтов, или, возможно, использовать функцию, связанную с ntonl, которая мне не ясна, какчто бы знать, если мой номер в правильном порядке или нет.

Что бы вы посоветовали для обеспечения совместимости, учитывая, что мне нужно формировать целые числа таким образом?

Ответы [ 4 ]

8 голосов
/ 13 апреля 2011

Пока вы работаете на уровне значение , в результатах, которые вы получаете, не будет абсолютно никакой разницы, независимо от того, является ли ваша машина прямым или старшим.Т.е., пока вы используете операторы языкового уровня (например, | и << в вашем примере), вы получите точно такой же арифметический результат из вышеприведенного выражения на любой платформе.Порядковый номер машины не обнаруживается и не виден на этом уровне.

Единственные ситуации, когда вам нужно заботиться о порядке байтов, - это когда данные, с которыми вы работаете, проверяются на уровне представления объекта , т. Е. В ситуациях, когда важно представление в необработанной памяти.То, что вы сказали выше о «AB BC CD DE вместо DE CD BC AB», конкретно относится к необработанному расположению памяти в данных.Вот что делают такие функции, как ntonl: они конвертируют один макет памяти в другой.До сих пор вы не указывали, что фактическая структура памяти в любом случае важна для вас.Это так?

Опять же, если вам нужно только значение вышеприведенного выражения, оно полностью и полностью не зависит от порядка байтов.По сути, вы вообще не должны заботиться о порядке байтов, когда пишете программы на С, которые не пытаются получить доступ к необработанному содержимому памяти и изучить его.

3 голосов
/ 13 апреля 2011

хотя это повлияет на мою работу полностью в том, что я буду смещаться неправильно (?)

номер

Результат будет одинаковым независимо от архитектуры байтов. Сдвиг битов и твидлинг - это как обычные арифметические операции. 2 + 2 одинаково на архитектурах с прямым и прямым порядком байтов? Конечно. 2 << 2 тоже самое.

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

char bytes[] = {1, 0, 0, 0};
int n = *(int*)bytes;

На машинах с прямым порядком байтов n будет равно 0x00000001. На машинах с прямым порядком байтов n будет равно 0x01000000. Это когда вам придется поменять местами байты.

1 голос
/ 13 апреля 2011

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

Вы можете определить 'порядковый номер' во время выполнения следующим образом:

#define LITTLE_ENDIAN 0
#define BIG_ENDIAN    1

int endian() {
    int i = 1;
    char *p = (char *)&i;

    if (p[0] == 1)
        return LITTLE_ENDIAN;
    else
        return BIG_ENDIAN;
}

... и действовать соответственно.

Я позаимствовал фрагмент кода здесь: http://www.ibm.com/developerworks/aix/library/au-endianc/index.html?ca=drs-, где также прекрасно обсуждаются эти вопросы.

hth -

Перри

1 голос
/ 13 апреля 2011

[Переписано для ясности]

ntohlntohs и т. Д.) Используется в основном для перемещения данных с одного компьютера на другой.Если вы просто манипулируете данными на одном компьютере, то совершенно нормально выполнять сдвиг битов без какой-либо дальнейшей церемонии - сдвиг битов (по крайней мере, в C и C ++) определяется с точки зрения умножения / деления на степени 2,поэтому он работает одинаково, независимо от того, является ли машина прямым или младшим.

Когда / если вам нужно (хотя бы потенциально) переместить данные с одного компьютера на другой, обычно целесообразно использовать htonlперед отправкой, и ntohl при получении.Это может быть полностью nops (в случае BE к BE), два идентичных преобразования, которые взаимно компенсируют (LE к LE), или фактически приводят к обмену байтами (LE к BE или наоборот).

...