Как я могу форсировать размер int для целей отладки?

У меня есть две сборки для части программного обеспечения, которую я разрабатываю, одна для встроенной системы, где размер int равен 16 битам, а другая для тестирования на настольном компьютере, где размер int равен 32 битам. Я использую целочисленные типы фиксированной ширины из <stdint.h>, но правила целочисленного продвижения по-прежнему зависят от размера int.

В идеале я хотел бы, чтобы следующий код печатал 65281 (целочисленное повышение до 16 бит) вместо 4294967041 (целочисленное повышение до 32 бит) из-за целочисленного повышения, чтобы оно точно соответствовало поведению во встроенной системе. Я хочу быть уверен, что код, который дает один ответ во время тестирования на моем рабочем столе, дает точно такой же ответ во встроенной системе. Решение для GCC или Clang было бы хорошо.

#include <stdio.h>
#include <stdint.h>

int main(void){
    uint8_t a = 0;
    uint8_t b = -1;

    printf("%u\n", a - b);

    return 0;
}

РЕДАКТИРОВАТЬ:

Пример, который я привел, возможно, не был лучшим примером, но я действительно хочу, чтобы целочисленное продвижение было до 16 бит вместо 32 бит. Возьмите следующий пример:

#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>

int main(void){
    uint16_t a = 0;
    uint16_t b = 1;
    uint16_t c = a - 2; // "-2": 65534
    uint16_t d = (a - b) / (a - c);

    printf("%" PRIu16 "\n", d);

    return 0;
}

Выходные данные равны 0 в 32-разрядной системе из-за усечения от целочисленного деления после перехода к (подписанному) целому числу, в отличие от 32767.

Лучшим ответом на данный момент, похоже, является использование эмулятора, а это не то, на что я надеялся, но, думаю, имеет смысл. Похоже, что для компилятора теоретически должно быть возможно сгенерировать код, который ведет себя так, как будто размер int равен 16 битам, но я думаю, что, возможно, не должно быть слишком удивительно, что на практике нет простого способа сделать это, и, вероятно, нет особого спроса на такой режим и какой-либо необходимой поддержки во время выполнения.

Ответы

Ответ 1

Вы не можете, если не найдете какой-то особенный компилятор. Это сломало бы абсолютно все, включая ваш вызов printf. Генерация кода в 32-битном компиляторе может даже не дать 16-битный арифметический код, поскольку это обычно не требуется.

Вы рассматривали возможность использования эмулятора вместо этого?

Ответ 2

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

Если вы хотите запустить свой 16-битный код в 32-битной системе, ваш наиболее вероятный шанс на успех - запустить его в chroot, который имеет сравнимую среду выполнения, возможно, используя qemu-user-static если вам тоже нужен перевод ISA, Тем не менее, я не уверен, что какая-либо из платформ, поддерживаемых QEMU, имеет 16-битный ABI.

Возможно, вам удастся написать набор 16-битных библиотек-оболочек, поддерживаемых вашими собственными библиотеками платформы, но я подозреваю, что эти усилия перевесят пользу для вас.

Обратите внимание, что для конкретного случая запуска 32-битных двоичных файлов x86 на 64-битном хосте amd64 ядра Linux часто конфигурируются с поддержкой двух ABI (конечно, вам все еще нужны соответствующие 32-битные библиотеки).

Ответ 3

Вы могли бы сделать сам код более осведомленным о размерах данных, которые он обрабатывает, например, выполнив:

printf("%hu\n", a - b);

Из документов fprintf:

час

Указывает, что следующий спецификатор преобразования d, i, o, u, x или X применяется к аргументу short int или unsigned short int (аргумент будет повышен в соответствии с целочисленными предложениями, но его значение должно быть преобразовано в short int или unsigned short int перед печатью);

Ответ 4

Не могли бы вы определить длину с помощью typedefs?

Я знаю, что TI делает это в своих встроенных программах. C99 определяет стандартные целочисленные типы, которые одинаковы для всех платформ. Использование этих переменных помогает сделать код переносимым, поскольку они абстрагируют различия между типами собственных переменных между различными архитектурами.

typedef   signed char   int8_t;
typedef unsigned char  uint8_t;
typedef          short  int16_t;
typedef unsigned short uint16_t;

а затем использовать эти typedefs в качестве вашего типа данных :)