Переносимость кода C для различных схем адресации памяти
Если я правильно понимаю, спецификация DCPU-16 для 0x10c описывает 16-битное адресное пространство, где каждое смещение обращается к 16-битному слову, а не к байту, как в большинстве других архитектур памяти. Это имеет некоторые любопытные последствия, например, я полагаю, что sizeof(char)
а также sizeof(short)
оба вернутся 1
,
Возможно ли сохранить код на C переносимым между такими разными схемами адресации памяти? О чем следует помнить?
редактировать: возможно, я должен был привести более конкретный пример. Допустим, у вас есть некоторый сетевой код, который работает с потоками байтов. Вы отбрасываете половину своей памяти, помещая только один байт на каждый адрес, чтобы код мог остаться прежним, или вы обобщаете все с помощью битовых сдвигов, чтобы иметь дело с N байтами на смещение?
edit2: ответы, кажется, сосредоточены на вопросе размеров типов данных, что не было смысла - я даже не должен был упомянуть это. Вопрос в том, как справиться с потерей способности обращаться к любому байту в памяти с указателем. Разумно ли ожидать, что код будет агностиком по этому поводу?
4 ответа
Это вполне возможно. Грубо говоря, базовые целочисленные типы данных C имеют размеры, которые поддерживают:
sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long)
Выше не совсем то, что говорит спецификация, но это близко.
Как указывает awoodland в комментарии, вы также ожидаете, что компилятор C для DCPU-16 будет иметь CHAR_BIT == 16
,
Бонус за то, что не предполагал, что DCPU-16 будет иметь sizeof (char) == 2
Это распространенная ошибка.
Когда вы говорите "потеря способности обращаться к байту", я предполагаю, что вы имеете в виду "бит-октет", а не "символ". Переносимый код должен только предполагать CHAR_BIT >= 8
, На практике архитектуры, не имеющие байтовой адресации, часто определяют CHAR_BIT == 8
и позволить компилятору генерировать инструкции для доступа к байту.
Я на самом деле не согласен с ответами, предлагающими: CHAR_BIT == 16
как хороший выбор. Я бы предпочел: CHAR_BIT == 8
, с sizeof(short) == 2
, Компилятор может обрабатывать сдвиг / маскирование, как это происходит для многих архитектур RISC, для байтового доступа в этом случае.
Я предполагаю, что Нотч пересмотрит и уточнит спецификацию DCPU-16; уже есть запросы на механизм прерывания и дальнейшие инструкции. Это эстетический фон для игры, поэтому я сомневаюсь, что в ближайшее время будут официальные спецификации ABI. Тем не менее, кто-то будет работать над этим!
Редактировать:
Рассмотрим массив char
в C. Компилятор упаковывает 2 байта в каждый собственный 16-битный word
памяти DCPU. Так что, если мы получим, скажем, 10-й элемент (индекс 9
), извлеките слово # [9 / 2] = 4 и извлеките байт # [9 % 2] = 1.
Пусть 'X' будет начальным адресом массива, а 'I' будет индексом:
SET J, I
SHR J, 1 ; J = I / 2
ADD J, X ; J holds word address
SET A, [J] ; A holds word
AND I, 0x1 ; I = I % 2 {0 or 1}
MUL I, 8 ; I = {0 or 8} ; could use: SHL I, 3
SHR A, I ; right shift by I bits for hi or lo byte.
Регистр A
содержит "байт" - это 16-битный регистр, поэтому верхнюю половину можно игнорировать. В качестве альтернативы, верхняя половина может быть обнулена:
AND A, 0xff ; mask lo byte.
Это не оптимизировано, но оно передает идею.
Равенство выглядит примерно так:
1 == sizeof(char) <= sizeof(short) <= sizeof(int) <= sizeof(long)
short
тип может быть 1
и на самом деле, может быть, вы даже хотите int
типа быть 1
слишком на самом деле (я не читал спецификации, но я предполагаю, что нормальный тип данных - 16 бит). Этот материал определяется компилятором.
Для практичности, компилятор может захотеть установить long
к чему-то большему, чем int
даже если это требует от компилятора дополнительной работы (например, реализации сложения / умножения и т. д. в программном обеспечении).
Это не проблема адресации памяти, а скорее вопрос гранулярности.
Да, вполне возможно портировать код C
с точки зрения передачи данных было бы целесообразно либо упаковать биты (или использовать сжатие), либо отправить в 16-битных байтах
поскольку процессор почти полностью взаимодействует только с (игровыми) внутренними устройствами, которые, вероятно, также будут все 16-битными, это не должно быть реальной проблемой
Кстати, я согласен, что CHAR_BIT
должно быть 16, так как (IIRC) каждый символ должен быть адресуемым, поэтому CHAR_BIT ==8
потребуется sizeof(char*) ==2
что сделает все остальное слишком сложным