您可以通過包含足夠大的值以使其無法放入int(每個規範)來強制它被無符號簽名。這對於> = sizeof int類型非常簡單,但unsigned char/short更加複雜,並且需要編譯器特定的打包。當然,實現技術上仍然可以將UINT_MAX表示爲一個無符號長整數......但這並不是我見過的。
#include <stdio.h> //only included for printf example
#include <limits.h>
#include <stdint.h>
/** set up some helper macros **/
#ifdef _MSC_VER
#define PACK(...) __pragma(pack(push, 1)) __VA_ARGS__ __pragma(pack(pop))
#else /* for gcc, clang, icc and others */
#define PACK(...) __VA_ARGS__ __attribute__((__packed__))
#endif
#define _PASTE(x,y) x ## y
#define PASTE(x,y) _PASTE(x,y)
/* __LINE__ added for semi-unique names */
#define U_ENUM(n, ...) \
enum n { __VA_ARGS__ , PASTE(U_DUMMY , __LINE__) = UINT_MAX }
#define UL_ENUM(n, ...) \
enum n { __VA_ARGS__ , PASTE(UL_DUMMY , __LINE__) = ULONG_MAX }
#define SZ_ENUM(n, ...) /* useful for array indices */ \
enum n { __VA_ARGS__ , PASTE(SZ_DUMMY , __LINE__) = SIZE_MAX }
#define ULL_ENUM(n, ...) \
enum n { __VA_ARGS__ , PASTE(ULL_DUMMY , __LINE__) = ULLONG_MAX }
#define UC_ENUM(n,...) \
PACK(enum n { __VA_ARGS__ , PASTE(UC_DUMMY , __LINE__) = UCHAR_MAX })
#define US_ENUM(n,...) \
PACK(enum n { __VA_ARGS__ , PASTE(US_DUMMY , __LINE__) = USHRT_MAX })
下面是一個檢查,看看它按預期工作:
typedef UC_ENUM(,a) A_t;
typedef US_ENUM(,b) B_t;
typedef U_ENUM(,c) C_t;
typedef UL_ENUM(,d) D_t;
typedef ULL_ENUM(,e) E_t;
typedef SZ_ENUM(,e) F_t;
int main(void) {
printf("UC %d,\nUS %d,\nU %d,\nUL %d,\nULL %d,\nSZ %d,\n",sizeof(A_t),
sizeof(B_t),sizeof(C_t),sizeof(D_t),sizeof(E_t),sizeof(F_t));
return 0;
}
更像一個標準的枚舉聲明這比簡單的版本我用,這需要一個額外的命名有少許不同參數最後枚舉,而不是__LINE__
黑客(這也是返回-1錯誤功能非常有用,因爲它會轉換爲U * _MAX) 下面是該版本的外觀:
#define U_ENUM(n, err, ...) enum n { __VA_ARGS__ , err = UINT_MAX }
#define UL_ENUM(n, err, ...) enum n { __VA_ARGS__ , err = ULONG_MAX }
#define ULL_ENUM(n,err, ...) enum n { __VA_ARGS__ , err = ULLONG_MAX}
#define SZ_ENUM(n, err, ...) enum n { __VA_ARGS__ , err = SIZE_MAX }
#define UC_ENUM(n, err, ...) PACK(enum n { __VA_ARGS__ , err = UCHAR_MAX })
#define US_ENUM(n, err, ...) PACK(enum n { __VA_ARGS__ , err = USHRT_MAX })
除了在char中包含枚舉或緊湊性之外,size_t枚舉最有趣,因爲它們可以用作數組索引而無需額外的MOV指令。
typedef SZ_ENUM(message_t,MSG_LAST,MSG_HELLO,MSG_GOODBYE,MSG_BAD) message_t;
static const char *messages[]={"hello","goodbye","bad message"};
void printmsg(message_t msg){
if (msg > MSG_BAD) msg = MSG_BAD;
(void) puts(messages[msg]);
}
注意:如果使用C++ 11 VS C,可以enum Foo : char { A, B, C};
或enum class Bar : size_t { X, Y, Z};
這是來自PC-LINT的一個愚蠢的警告。 'x2'的值是靜態已知的,並且已知適合'uint8_t'的範圍,所以類型是無關緊要的。同樣愚蠢的是發出'char x = 1LL;'的警告。 –
@R ..問題在於MISRA與PC-Lint無關。 'uint8_t x = 1;'不符合MISRA-C,它不需要在已簽名和未簽名類型之間進行隱式轉換。 – ouah
這是MISRA關於枚舉的一個問題:枚舉常量和枚舉變量不一定具有相同的類型,因此它們不一定是兼容的。這是C語言中許多奇怪的不一致之處,也不是MISRA的錯,它們只是試圖避開語言的所有這些非理性缺陷。 – Lundin