关于C11 _Generic兼容类型合规性及添加stdint.h类型的技术问询
关于
_Generic与定宽整数类型的问题解答 1. uint64_t与unsigned long long int共存于_Generic是否违反C17标准?
根据C17标准规定:
同一泛型选择中的任意两个泛型关联不得指定兼容类型。控制表达式的类型是其经过左值转换后的类型[……]
如果uint64_t是unsigned long long int的typedef,二者属于兼容类型——typedef仅为已有类型起别名,本质类型并未改变。因此同时在_Generic的泛型关联中指定这两个类型,直接违反了C17的这条规则。
这种情况下,标准要求编译器必须给出诊断信息(警告或错误),是否编译失败取决于编译器配置(部分编译器会将这类违规视为错误终止编译,部分仅触发警告)。但这不属于未定义行为,因为标准明确要求对该类违规情况进行诊断。
另外需要注意:_Generic最初是为提升<math.h>实现的可移植性设计的,处理整数类型时需警惕char、short int被提升为int的情况,这类小整数类型的左值转换结果会改变控制表达式的实际类型,导致_Generic匹配到非预期的分支。
2. 给map宏添加stdint.h定宽类型的潜在问题
针对给出的map宏:
#define map(count, iter, func) _Generic (*iter, \ char: map_c, \ unsigned char: map_uc, \ short int: map_si, \ unsigned short int: map_usi, \ int: map_i, \ unsigned int: map_ui, \ long int: map_li, \ unsigned long int: map_uli, \ long long int: map_lli, \ unsigned long long int: map_ulli, \ float: map_f, \ double: map_d, \ long double: map_ld, \ _Bool: map_b, \ char *: map_s \ )(count, iter, func)
添加stdint.h定宽类型时,主要存在以下潜在问题:
- 兼容类型冲突:定宽类型多是基础类型的typedef(如
uint64_t对应unsigned long long int、int32_t对应int),添加后会和宏中已有的基础类型形成兼容类型对,违反_Generic的规则,触发编译器诊断。 - 平台依赖的匹配歧义:定宽类型的底层实现随平台变化,比如
int64_t在部分平台是long int,在另一部分平台是long long int。若宏中同时保留基础类型和定宽类型,不同平台下同一实际类型可能匹配到不同分支,导致行为不一致。 - 冗余与维护负担:添加定宽类型会让宏结构变得臃肿,且需要针对不同平台的typedef情况做兼容处理,增加维护成本,反而降低代码可移植性。
- 整数提升导致的匹配失效:像
int8_t这类定宽类型本质是signed char,会被左值转换提升为int,此时_Generic的控制表达式类型是提升后的int,无法匹配到宏中指定的int8_t分支。
内容的提问来源于stack exchange,提问作者Madagascar
相关产品推荐
相关产品推荐

