WedX - журнал о программировании и компьютерных науках

Как легко извлечь 2x int16 из int32?

У меня есть переменная с двумя значениями int16:

int32_t value = 0x1234ABCD; // a=0x00001234, b=0xFFFFABCD

Наивное решение - сделать маску:

int32_t a = (value & 0xFFFF0000) >> 16;
int32_t b = (value & 0x0000FFFF);

Но с этим у меня нет никакого расширения знака, и b становится 0x0000ABCD вместо 0xFFFFABCD.

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

struct dual_int16 {
   long hi:16;
   long lo:16;
}

int32_t a = (struct dual_int16)value).lo;
int32_t a = (struct dual_int16)value).hi;

К сожалению, мой компилятор не позволяет мне делать это: «struct dual_int16 не разрешена» или «тип приведения должен быть арифметическим или указателем».

Есть ли правильный способ извлечь мой 2x int16 с расширением знака в C99?

ИЗМЕНИТЬ

Потому что я использую конкретный компилятор (ADSP-21xxx). У меня нет всех стандартных типов, определенных в stdint.h, таких как int16_t. Мой компилятор не распознает int8_t и int16_t.

Арка имеет гибридный 32-48битный двойной ALU с прямым порядком байтов.

c
10.12.2014

  • Вы пробовали преобразовать в int16_t перед преобразованием в 32 бита? 10.12.2014
  • Вы можете попробовать сохранить 16-битные значения в 16-битном типе. 10.12.2014
  • Что заставляет вас думать, что 0x1234ABCD & 0x0000FFFF должен стать 0xFFFFABCD? 10.12.2014
  • Вы хотите int16, но определяете результат как int32. Результат нормальный. 10.12.2014
  • @BennoZeeman Потому что я храню 2x int16. 0xABCD = -21555. Если вы сделаете расширение знака, окончательное значение станет 0xFFFFABCD = -21555 10.12.2014
  • @coin В каком компиляторе есть int32_t, но нет int16_t? 10.12.2014
  • в порядке. так что, возможно, вам нужно написать код для конкретной архитектуры. может быть, вы могли бы предложить нам информацию о порядке байтов, длину short, int и long и какую стандартную библиотеку у вас есть. 10.12.2014
  • возможно, мы сможем исследовать больше. правый сдвиг в арифметике или логике вашего компилятора? 10.12.2014
  • Это может быть и то, и другое в зависимости от бита конфигурации. Конечно, я могу использовать макрос сборки, который поможет. Но я ищу более портативное решение 10.12.2014

Ответы:


1

union сделает свое дело.

union {
    int32_t value;
    struct {
        int16_t v1, v2;
    } decomp;
} extract;

/* ... */
extract.value = value;
int32_t a = extract.decomp.v1, b = extract.decomp.v2;

обратите внимание, что a и b имеют желаемые знаки.

10.12.2014
  • Может работать, но требует больше усилий и более подвержено ошибкам, чем ручное маскирование и смещение. Не весь мир имеет прямой порядок байтов. 10.12.2014
  • @ Дедупликатор, да. на самом деле с прямым порядком байтов, это тоже поможет. но v1 и v2 в обратном порядке. не обязательно быть более подверженным ошибкам, чем ручной сдвиг, поскольку они фактически одинаковы. 10.12.2014
  • Никогда не читайте участника, которому написал другой участник. 10.12.2014
  • Вы должны читать только то поле, которое было написано последним. 10.12.2014
  • Извините, на данный момент я не могу найти его в стандарте. Но у меня есть ответ, который меня поддерживает. 10.12.2014
  • @BennoZeeman больше нет в c99, потому что значение затрагивает весь союз, который вам разрешено читать из v1 и v2. Чтение значения после записи в v1 не допускается. 10.12.2014
  • Декомпозиция битовой / байтовой последовательности @BennoZeeman с использованием union - это обычный прием в C, широко используемый в низкоуровневом программировании. 10.12.2014
  • C99, 6.2.6.1: Когда значение сохраняется в члене объекта типа union, байты представления объекта, которые не соответствуют этому члену, но соответствуют другим членам, принимают неопределенные значения. Я немного сейчас потеряна, но я почти уверен, что людям следует избегать этого, если они могут. Низкоуровневое программирование отличается, потому что обычно вы ориентируетесь на конкретную архитектуру и т. Д. 10.12.2014
  • @BennoZeeman да. иногда люди избегают этого, если вы определяете union для представления выбора. это что-то вроде struct { enum myenum choice; union { /* some structs */ } value; }. но в моем случае это должно работать именно так. нет необходимости нацеливаться на конкретную арку, если вы декомпозируете поток в TCP / IP, вы также будете счастливы использовать union. 10.12.2014

  • 2

    Если вам нужны 16-битные значения со знаком, используйте правильный тип:

    #include <stdint.h>
    
    const int32_t value = 0x1234ABCD; // a=0x00001234, b=0xFFFFABCD
    
    const int16_t a = (value >> 16) & 0xffff;
    const int16_t b = value & 0xffff;
    
    printf("a=%hd\nb=%hd\n", (short) a, (short) b);
    

    Это печатает:

    a=4660
    b=-21555
    

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

    Я использовал int16_t, так как вы использовали uint32_t и упомянули C99, это действительно заставило меня поверить, что он у вас должен быть. Убедитесь, что вы #include <stdint.h>.

    10.12.2014
  • Если OP нужно сохранить их в int32_t, я думаю, вы могли бы неявно преобразовать int16_t в int32_t с помощью int32_t a = (uint16_t)((value >> 16) & 0xffff);. 10.12.2014
  • Я действительно не понимаю, что такое (uint16_t), это не то, что ты сказал, что хочешь сделать ... Я довольно скептически отношусь к этому предложению. 10.12.2014
  • Мне ужасно жаль. Я имел в виду int16_t. Думаю, вы меня запутали, упомянув uint32_t в своем ответе. О, Боже. 10.12.2014
  • Что касается уменьшения буквального размера, вы все равно не захотите делать (value & 0xFFFFFFFF) >> 16, потому что сдвиг вправо отрицательного целого числа является поведением, определяемым реализацией: вы не знаете, заполнится ли оно нулями (логический сдвиг) или битом знака ( арифметический сдвиг). Написанный вами код позволяет избежать этой проблемы, поскольку вы маскируете нежелательные биты после сдвига. 10.12.2014
  • @Lundin Это правда, и, возможно, еще одна причина, по которой я давно перешел на этот шаблон. :) Спасибо. 10.12.2014
  • Да и кстати ... никто не ожидает неявного целочисленного продвижения! Шестнадцатеричный литерал больше 0x7fff на самом деле имеет беззнаковый тип в 16-битной системе. Это означает, что value & 0xffff будет повышен до беззнакового типа, поскольку тогда 0xffff фактически имеет тип unsigned int. Это потенциально могло вызвать ошибку, но, насколько я понимаю, этот конкретный код будет в порядке. Смешивание целых чисел со знаком с поразрядными операторами всегда опасно. 10.12.2014

  • 3
    short a = (short)( (value >> 16) & 0xFFFF );
    short b = (short)( value & 0xFFFF );
    

    int32_t также не является стандартным типом (комментарий к @coin). short/short int эквивалентно int16_t.

    10.12.2014
  • Что вы имеете в виду, говоря, что int32_t не является стандартным типом? sizeof (короткий) может быть ›2. 10.12.2014
  • Может быть, а может и не быть эквивалентом. И это стандартный -typedef, если у реализации есть подходящий тип на C99 (и, вероятно, с обратным портированием). 10.12.2014
  • Это комментарий сверху: К сожалению, int16_t не существует в моем компиляторе. По этой причине я говорю, что int32_t также не является нормальным типом. 10.12.2014
  • Новые материалы

    Как создать диаграмму градиентной кисти с помощью D3.js
    Резюме: Из этого туториала Вы узнаете, как добавить градиентную кисть к диаграмме с областями в D3.js. Мы добавим градиент к значениям SVG и применим градиент в качестве заливки к диаграмме с..

    Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что это выглядит сложно…
    Просто начните и учитесь самостоятельно Я хотел выучить язык программирования MVC4, но не мог выучить его раньше, потому что он кажется мне сложным, и я бросил его. Это в основном инструмент..

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

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..


    Для любых предложений по сайту: [email protected]