Как стандартные целые числа из <stdint.h> переводятся во время компиляции?
В Си распространено (или по крайней мере возможно) предназначаться для различных архитектур процессора с тем же самым исходным кодом. Также часто архитектуры процессоров по-разному определяют целочисленные размеры. Чтобы увеличить переносимость кода и избежать ограничений целочисленного размера, рекомендуется использовать стандартный целочисленный заголовок языка C. Тем не менее, я запутался в том, как это на самом деле реализовано.
Если бы я написал небольшую программу на C, написанную для x86, а затем решил перенести ее на 8-битный микроконтроллер, как компилятор микроконтроллера узнал, как преобразовать uint32_t в его собственный целочисленный тип?
Есть ли какое-то требование отображения при написании компиляторов Си? Например, если ваш компилятор должен быть совместим с C99, вам нужна функция отображения, которая заменяет все uint32_t на собственный тип?
Спасибо!
3 ответа
Типично <stdint.h>
содержит эквивалент
typedef int int32_t;
typedef unsigned uint32_t;
с фактическим выбором типа, подходящим для текущей машины.
В действительности это часто намного сложнее, с множеством дополнительных, вспомогательных заголовочных файлов и вспомогательных макросов препроцессора, но эффект тот же: имена похожи uint32_t
в конечном итоге это настоящие имена типов, как если бы они определялись typedef
,
Вы спросили: "Если ваш компилятор должен быть совместим с C99, вам нужна функция отображения?", И ответ в основном "да", но "функцией отображения" могут быть только те типы, которые автор компилятора выбирает в своем распределенном копия stdint.h
, (Чтобы ответить на ваш другой вопрос, да, есть как минимум столько же <stdint.h>
там, где есть компиляторы; нет ни одной мастер-копии или чего-либо еще.)
Односторонний комментарий. Вы сказали: "Чтобы увеличить переносимость кода и избежать ограничений целочисленного размера, рекомендуется использовать стандартный целочисленный заголовок языка Си". Настоящая рекомендация - использовать этот заголовок, когда у вас есть особые требования, например, для размеров с точным типом. Если по какой-то причине вам нужен подписанный тип, скажем, ровно 32 бита, то непременно используйте int32_t
от stdint.h
, Но в большинстве случаев вы обнаружите, что "простые" типы, такие как int
а также long
отлично в порядке. Пожалуйста, не позволяйте никому говорить вам, что вы должны выбрать точный размер для каждой объявленной вами переменной и использовать имя типа для stdint.h
объявить это с.
Обработка различных архитектур, скорее всего, реализуется с помощью директив условной предварительной обработки, таких как #if
или же #ifdef
, Например, на платформе GNU/Linux это может выглядеть так:
# if __WORDSIZE == 64
typedef long int int64_t;
# else
__extension__
typedef long long int int64_t;
# endif
Никакого волшебства не происходит, в форме "картирования" или "перевода": stdint.h
просто содержит список typedef
заявления. Разница заключается в генераторе кода, а не в интерфейсе компилятора.
Для 8-битной цели генератор кода будет использовать собственные инструкции для арифметики для любых типов, которые он изначально поддерживает (возможно, есть 16-битная инструкция добавления). В остальном он будет вставлять вызовы в библиотечные подпрограммы для реализации больших типов данных.
В RTL 8-битного компилятора нередко содержатся такие подпрограммы, как "long_add", "long_subtract" и так далее.