Простая побитовая манипуляция для мало-endian целых чисел, в машинах большого размера?

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

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

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

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

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

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

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

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

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

    Нет.

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

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

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

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

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

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

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

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

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

     #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; } 

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

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

    hth –

    грушевый сидр