types安全在C

有没有办法使C更加了解types并确保types安全?
考虑一下:

typedef unsigned cent_t; typedef unsigned dollar_t; #define DOLLAR_2_CENT(dollar) ((cent_t)(100*(dollar))) void calc(cent_t amount) { // expecting 'amount' to semantically represents cents... } int main(int argc, char* argv[]) { dollar_t amount = 50; calc(DOLLAR_2_CENT(amount)); // ok calc(amount); // raise warning return 0; } 

有没有办法让上面的代码至less提醒gcc的警告?
我知道我可以使用C结构来包装unsigned s,并达到预期的结果,我只是想知道是否有一个更优雅的方式来做到这一点。
它可以比这更多一点吗?

您需要在构build过程中使用静态分析工具来实现此目的。

例如,如果您在代码上运行PCLint,则会提供以下输出:

  [Warning 632] Assignment to strong type 'cent_t' in context: arg. no. 1 [Warning 633] Assignment from a strong type 'dollar_t' in context: arg. no. 1 

http://www.gimpel.com/html/strong.htm

问题是C不会把你的两个typedefs当作独特的types,因为它们都是unsignedtypes的。

有各种各样的技巧闪避这一点。 有一件事是将你的types改为枚举。 良好的编译器会对从某个枚举types到其他types的隐式转换实施更强的types警告。

即使你没有一个好的编译器,使用枚举你可以这样做:

 typedef enum { FOO_CENT } cent_t; typedef enum { FOO_DOLLAR} dollar_t; #define DOLLAR_2_CENT(dollar) ((cent_t)(100*(dollar))) void calc(cent_t amount) { // expecting 'amount' to semantically represents cents... } #define type_safe_calc(amount) _Generic(amount, cent_t: calc(amount)) int main(int argc, char* argv[]) { dollar_t amount = 50; type_safe_calc(DOLLAR_2_CENT(amount)); // ok type_safe_calc(amount); // raise warning return 0; } 

一个更传统的/传统的技巧是使用一个通用的结构包装器,在那里你使用“票”枚举来标记types。 例:

 typedef struct { type_t type; void* data; } wrapper_t; ... cent_t my_2_cents; wrapper_t wrapper = {CENT_T, &my_2_cents}; ... switch(wrapper.type) { case CENT_T: calc(wrapper.data) ... } 

好处是它可以与任何C版本一起使用。 缺点是代码和内存开销,它只允许运行时检查。

C中的别名有一个非常狭义的含义,这不是你想到的。 你可能想说“typedefing”。

答案是否定的,你不能。 无论如何,没有一个优雅的方式。 你可以为每个数字types使用一个结构体,并使用一组独立的函数来对每一个进行math运算。 除了乘法,你运气不好。 为了乘以磅英尺,你需要第三种types。 你还需要脚的types,脚的立方,秒的力量减去两个和其他types的无限数量。

如果这就是你所追求的,那么C就不是正确的语言。

编辑:这里的替代工程,即使在C89,如果你的编译器不支持_Genericselect器(很多编译器不经常,你经常被困在你的机器上安装的东西)。

您可以使用macros来简化struct包装器的使用。

 #define NEWTYPE(nty,oty) typedef struct { oty v; } nty #define FROM_NT(ntv) ((ntv).v) #define TO_NT(nty,val) ((nty){(val)}) /* or better ((nty){ .v=(val)}) if C99 */ NEWTYPE(cent_t, unsigned); NEWTYPE(dollar_t, unsigned); #define DOLLAR_2_CENT(dollar) (TO_NT(cent_t, 100*FROM_NT(dollar))) void calc(cent_t amount) { // expecting 'amount' to semantically represents cents... } int main(int argc, char* argv[]) { dollar_t amount = TO_NT(dollar_t, 50); // or alternatively {50}; calc(DOLLAR_2_CENT(amount)); // ok calc(amount); // raise warning return 0; } 

你甚至比警告更强。 这是gcc 5.1的编译结果

 $ gcc -O3 -Wall Edit1.c
 Edit1.c:在函数'main'中:
 Edit1.c:17:10: error :'calc'的参数1的不兼容types
     计算值(量);  //提出警告
           ^
 Edit1.c:10:6: note :expected'cent_t {aka struct}'但是参数的types是'dollar_t {aka struct}'
  void calc(cent_t amount); // {

这里的结果与海湾合作委员会3.4

 $ gcc -O3 -Wall Edit1.c
 Edit1.c:在函数'main'中:
 Edit1.c:17:error:'calc'的参数1的不兼容types