2014-09-01 1 views
1

Может кто-нибудь объяснить мне, что может случиться, если я забуду суффикс (постфикс) для констант (литералов) в ANSI C?C буквальный суффикс U, проблемы UL

Например, я видел для операций побитового сдвига таких устанавливает:

#define AAR_INTENSET_NOTRESOLVED_Pos (2UL) /*!< Position of NOTRESOLVED field. */ 
#define AAR_INTENSET_NOTRESOLVED_Msk (0x1UL << AAR_INTENSET_NOTRESOLVED_Pos) /*!< Bit mask of NOTRESOLVED field. */ 
#define AAR_INTENSET_NOTRESOLVED_Disabled (0UL) /*!< Interrupt disabled. */ 
#define AAR_INTENSET_NOTRESOLVED_Enabled (1UL) /*!< Interrupt enabled. */ 
#define AAR_INTENSET_NOTRESOLVED_Set (1UL) /*!< Enable interrupt on write. */ 

Он используется в 32-битной архитектуре. Но его можно было портировать на 16 или 8 бит. Что может случиться, если postfix UL не используется, и я буду использовать эти макросы для операций сдвига бит, как предполагается?

Я просто предполагаю, что, например, в 8-битной архитектуре может (1 < < 30) приводит к переполнению.

EDIT: Я нашел хорошую ссылку: http://dystopiancode.blogspot.cz/2012/08/constant-suffixes-and-prefixes-in-ansi-c.html

Но это безопасно использовать суффиксы, если код должен быть перенесен на различных архитектурах?

Например, если суффикс U представляет собой unisgned int, поэтому для 8-битной архитектуры обычно 16 бит, но для 32-битной переменной 32 бит, поэтому 0xFFFFAAAAU подходит для 32-битного компилятора,

+2

«8-разрядная архитектура» не равна «может рассчитывать только до 255». Компилятор должен переводить вычисления большего размера, чем шины, в куски, которые легче усваиваются. – usr2564301

ответ

5

десятичное число, как -1,1,2,12345678 и т.д. без суффикса получит наименьший тип это будет соответствовать, начиная с int, long, long long.

Восьмеричная или шестнадцатеричное число, как 0, 0123, 0x123, 0X123 без суффикса получит наименьший тип это будет соответствовать, начиная с int, unsigned, long, unsigned long, long long, unsigned long long.


Ниже потенциальная проблема должна превышать AAR_INTENSET_NOTRESOLVED_Pos 31. Примечание: unsigned long должны быть мере 32 бит. Это приведет к 0 **, если unsigned long было 32 бита, но отличное от нуля, если оно больше.

(0x1UL << AAR_INTENSET_NOTRESOLVED_Pos) 

Ниже приводится аналогичная потенциальная проблема должна превышать AAR_INTENSET_NOTRESOLVED_Pos 15. 0x1 является unsigned, который должен быть только по меньшей мере, 16 бит. Также, если unsigned/int - 16 бит, минимум 0x1 будет int. Таким образом, без явного использования U, 0x1 может быть проблемой, если AAR_INTENSET_NOTRESOLVED_Pos == 15.[@ Matt Макнэбб]

(0x1 << AAR_INTENSET_NOTRESOLVED_Pos) 

Битовых операторы сдвига
«Целые акции выполняются на каждом из операндов. Тип результата является то, что продвигаемым левым операндом. Если значение правильного операнда отрицательный или больше или равен ширине продвинутого левого операнда, поведение не определено ». C11dr §6.5.7 3


Ширина станка не является ключевой проблемой. 8-битная или 16-битная машина может использовать 16, 32 и т. Д. Размер бит int. Опять же, 16 бит - это минимальный размер для совместимого компилятора C.


[изменить] ** я должен был сказать «Это (смещение больше, чем 31 бита) может привести к непредсказуемому поведению, УБ, если unsigned long был 32 бита.»

+0

OK ... '0x1 << 15' также вызывает UB (знак целочисленного переполнения), если' int' является 16-битным, поэтому значение «превышает 15» должно быть «равно или больше 15» или аналогично –

+0

@Matt McNabb Спасибо за указание ошибка тоже исправлена. – chux

0

Это может сломаться.

Было бы лучше включить бросок в самом коде, т.е.

uint32_t something = (uint32_t) AAR_INTENSET_NOTRESOLVED_Set << 30; 

Это делает его работу, даже если #define для константы просто целое число.