В чем разница между приведением long к int и использованием побитового И для получения 4 младших байтов? - PullRequest
0 голосов
/ 28 мая 2019

Я знаю, что для получения 4 младших байтов числа типа long я могу привести его к int / unsigned int или использовать побитовое И (& 0xFFFFFFFF).

Этот код дает следующий вывод:

#include <stdio.h>

int main()
{
  long n = 0x8899AABBCCDDEEFF;
  printf("0x%016lX\n", n);
  printf("0x%016X\n", (int)n);
  printf("0x%016X\n", (unsigned int)n);
  printf("0x%016lX\n", n & 0xFFFFFFFF);
}

Вывод:

0x8899AABBCCDDEEFF
0x00000000CCDDEEFF
0x00000000CCDDEEFF
0x00000000CCDDEEFF

Означает ли это, что оба используемых метода эквивалентны?Если да, то всегда ли они выдают один и тот же вывод независимо от платформы / компилятора?
Кроме того, есть ли ловушка или ловушка при приведении к unsigned int вместо int для целей этого вопроса?
Наконецпочему вывод такой же, если вместо номера n указать unsigned long?

Ответы [ 3 ]

2 голосов
/ 28 мая 2019

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

Что касается второго вопроса, то он сводится к следующему: long и int подписываются, что означает, что один бит зарезервирован для знака (взгляните также на дополнение к двум ). Если вы были компилятором, что вы можете сделать с отрицательными значениями (особенно с длинными)? Как отметил Степан Лехнер, это определяется реализацией (то есть зависит от компилятора).

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

1 голос
/ 28 мая 2019

В чем разница между приведением long к int и использованием побитового И для получения 4 младших байтов?

Тип.Кастинг делает значение int.And'ing не меняет тип.

Диапазон.В зависимости от диапазона int,long приведение может вообще не изменять значение.

IDB и UB. определенное реализацией поведение и неопределенное поведение присутствуют со смешанным знаком.

Чтобы "получить" 4 LSBytes, используйте & 0xFFFFFFFFu или приведите к uint32_t.


Вопрос OP излишне запутан.

long n = 0x8899AABBCCDDEEFF; -> Преобразование значения вне диапазона целочисленного типа со знаком является реализацией -определенный .

В противном случае новый тип подписывается и значение не может быть представлено в нем;либо результат определяется реализацией, либо генерируется определяемый реализацией сигнал.
C11 §6.3.1.3 3

printf("0x%016lX\n", n); -> Печать long с "%lX"вне общего диапазона long/unsigned long - неопределенное поведение .


Давайте продолжим с unsigned long:

  unsigned long n = 0x8899AABBCCDDEEFF;  // no problem,
  printf("0x%016lX\n", n);               // no problem,
  printf("0x%016X\n", (int)n);           // problem, C11 6.3.1.3 3
  printf("0x%016X\n", (unsigned int)n);  // no problem,
  printf("0x%016lX\n", n & 0xFFFFFFFF);  // no problem,

«Нет проблем»все в порядке, даже если unsigned long является 32-разрядным или 64-разрядным.Выход будет отличаться, но все в порядке.

Напомним, что int,long не всегда 32,64 бит.(16,32), (32,32), (32,64) являются общими.

int равно не менее 16 бит.
long равно по крайней мере , что int и по крайней мере 32 бит.


1 голос
/ 28 мая 2019

Методы определенно различны.

Согласно интегральным правилам преобразования (см., Например, этот онлайн-стандарт c ++ 11), преобразование (например, посредством явного преобразования)от одного целочисленного типа к другому зависит от того, является ли тип назначения подписанным или неподписанным.Если тип назначения не имеет знака, можно полагаться на усечение «по модулю 2n», тогда как с типами назначения со знаком можно использовать поведение, определяемое реализацией:

4.7 Интегральные преобразования [conv.integral]

2 Если тип назначения не имеет знака, результирующее значение является целочисленным с наименьшим числом без знака, соответствующим исходному целому числу ( по модулю 2n, где n - количество битов, используемых для представления типа без знака).[Примечание: в представлении дополнения до двух это преобразование является концептуальным, и в битовой комбинации нет изменений (если нет усечения).- примечание конца]

3 Если тип назначения подписан, значение не изменяется, если оно может быть представлено в типе назначения (и ширине битового поля); в противном случае значение определяется реализацией.

...