Написание двоичных литералов на C без stdio.h или math.h?
Итак, мне нужно написать двоичные литералы на C. Мой компилятор не понимает двоичные литералы. Я знаю, что есть расширение gcc для "0b", но это не вариант. Прежде чем сказать: "Зачем тебе это нужно? Хекс был изобретен по какой-то причине, нуб", выслушай меня...
Это в целях маскировки. Я портирую игру с Sega Genesis/Megadrive на Sega Saturn. Столкновение в указанной игре использует плитки 16x16. Каждый фрагмент 16x16 имеет двухбайтовое значение в формате SSTT YXII IIII IIII. SS - это надежность элемента мозаичного изображения в альтернативном слое столкновений, TT - это надежность элемента мозаичного изображения в слое нормального столкновения. 00 означает не сплошной, 01 означает верхний сплошной, 10 означает левый / правый / нижний сплошной, а 11 означает все сплошной. Y- флаг Y-flip, X- флаг X-flip, а II IIII IIII - это индекс плитки 16x16 для использования.
Вы можете (надеюсь) увидеть, почему я хотел бы представить их в двоичном виде. Я собираюсь написать 100-е из них, и гораздо проще думать о твердости в битах, а не о гексагоне. Гораздо проще взглянуть на 0b0110 и сказать: "Хорошо, мозаика альтернативных столкновений сверху вниз, а нормальная - снизу", чем смотреть 0x6 и делать то же самое. Если бы я хотел изменить вторую плитку так, чтобы она также была в верхней части, я бы просто изменил 0110 на 0101, чем понял, что мне нужно изменить 6 на 5. Надеюсь, вы понимаете, почему я хочу, чтобы она была записана в двоичном виде. Это один раз, когда проще.
В любом случае, я работаю над Sega Saturn. Это означает, что я застрял с каким-либо компилятором C (на самом деле я даже не уверен, какой это компилятор или какая версия C), поэтому я не могу использовать stdio.h, math.h или что-нибудь. Черт, мне пришлось написать макрос по модулю.
Я видел некоторые дурацкие (но работоспособные) решения, но все они, похоже, требуют stdio... Я бы предпочел, чтобы это был макрос или что-то такое, что компилятор достаточно умен, чтобы его пропустить. Каждый цикл и бит оперативной памяти имеют значение, когда вы работаете с 16 мегабитами оперативной памяти, но я бы предпочел написать 0101 0011 1111, а не 53f. Двоичный файл имеет очень простой для понимания формат, и я хотел бы написать его таким образом.
Заранее спасибо!
3 ответа
Для того, что вы хотите, я бы написал макрос:
#define TILE_VALUE(S, T, Y, X, I) (((S) << 14) | ((T) << 12) | ((Y) << 11) | ((X) << 10) | (I))
Затем вы определяете инициализатор таблицы с помощью этого макроса
Вы можете использовать макросы как это:
#define BIN2(dig1, dig2) (dig1 << 1 | dig2)
#define BIN3(dig1, dig2, dig3) (dig1 << 2 | dig2 << 1 || dig3)
и так далее, сколько нужно для реализации. Тогда эквивалент 0b110
было бы BIN3(1, 1, 0)
,
Используйте макрос препроцессора для определения слов столкновения. Например,
#define BIT_PAIR_00 0
#define BIT_PAIR_01 1
#define BIT_PAIR_10 2
#define BIT_PAIR_11 3
#define BINARY2(nn) (BIT_PAIR_ ## nn)
#define COLLISION_PACK(ss, tt, yx, index) ((index & 0x3FF) | (BINARY2(ss) << 14) | (BINARY2(tt) << 12) | (BINARY2(yx) << 10) )
который позволяет вам использовать, например,
COLLISION_PACK(01, 00, 11, 142) == 0x4c8e == 0b0100110010001110
COLLISION_PACK(00, 10, 00, 200) == 0x20c8 == 0b0010000011001000
COLLISION_PACK(10, 01, 00, 0x1fe) == 0x91fe == 0b1001000111111110
Также можно использовать макросы для аргументов:
#define NONE 0u
#define TOP 1u
#define NOT_TOP 2u
#define ALL 3u
#define NO_FLIP 0u
#define FLIP_X 1u
#define FLIP_Y 2u
#define FLIP_XY 3u
#define COLLISION_PACK(ss, tt, flip, index) \
( ((index) & 0x3FFu) | \
(((flip) & 3u) << 10) | \
(((tt) & 3u) << 12) | \
(((ss) & 3u) << 14) )
который позволяет вам использовать, например,
COLLISION_PACK(SOLID_NONE, SOLID_NONE, FLIP_NONE, 1)
== 0x0001 == 0b0000000000000001 == 00 00 00 0000000001
COLLISION_PACK(SOLID_NOTTOP, SOLID_TOP, FLIP_X, 2)
== 0x9402 == 0b1001010000000010 == 10 01 01 0000000010
COLLISION_PACK(SOLID_ALL, SOLID_NOTTOP, FLIP_XY, 0x1fe)
== 0xedfe == 0b1110110111111110 == 11 10 11 0111111110