您可以通过包含一个足够大的值来强制它成为无符号数,以至于它不能适应 int(根据规范)。对于大小 >= sizeof int 的类型来说,这非常简单,但是对于 unsigned char/short 来说则更加复杂,需要编译器特定的打包。当然,实现技术上仍然可以将 UINT_MAX 表示为 unsigned long long……虽然我从未见过。
#include <stdio.h>
#include <limits.h>
#include <stdint.h>
#ifdef _MSC_VER
#define PACK( ... ) __pragma( pack(push, 1) ) __VA_ARGS__ __pragma( pack(pop) )
#else
#define PACK( ... ) __VA_ARGS__ __attribute__((__packed__))
#endif
#define _PASTE(x,y) x ## y
#define PASTE(x,y) _PASTE(x,y)
#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, ... ) \
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或short以节省空间外,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而不是C语言,您可以使用以下代码:
enum Foo : char { A, B, C};
或者
enum class Bar : size_t { X, Y, Z};
。
x2
的值在编译期就已经确定,并且已知它适合于uint8_t
范围内的取值,因此类型无关紧要。同样愚蠢的是针对char x = 1LL;
发出警告。 - R.. GitHub STOP HELPING ICEuint8_t x = 1;
不符合MISRA-C的规定,该规定要求有符号类型和无符号类型之间不得进行隐式转换。 - ouahenum {BLA_THIS, BLAH_THAT, BLAH_N };
其中枚举的最后一项只是枚举项的计数器。然后,您可以像for(int i=0; i<BLAH_N; i++) handle_each_possible_enum_value(my_enum);
这样使用该枚举计数器以处理每个可能的枚举值。 - Lundin