2008-12-13 96 views
3

我被限制为C(不能使用C++)。我希望C有更严格的类型检查。强制编译错误,如果函数参数超出范围

有没有办法在注释行上得到编译错误?如果有帮助,枚举值不能重叠。


enum hundred { 
    VALUE_HUNDRED_A = 100, 
    VALUE_HUNDRED_B 
}; 

enum thousand { 
    VALUE_THOUSAND_A = 1000, 
    VALUE_THOUSAND_B 
}; 

void print_hundred(enum hundred foo) 
{ 
    switch (foo) { 
     case VALUE_HUNDRED_A:  printf("hundred:a\n");  break; 
     case VALUE_HUNDRED_B:  printf("hundred:b\n");  break; 
     default: printf("hundred:error(%d)\n", foo); break; 
    } 
} 

void print_thousand(enum thousand bar) 
{ 
    switch (bar) { 
     case VALUE_THOUSAND_A:  printf("thousand:a\n");  break; 
     case VALUE_THOUSAND_B:  printf("thousand:b\n");  break; 
     default: printf("thousand:error(%d)\n", bar); break; 
    } 
} 

int main(void) 
{ 
    print_hundred(VALUE_HUNDRED_A); 
    print_hundred(VALUE_THOUSAND_A); /* Want a compile error here */ 

    print_thousand(VALUE_THOUSAND_A); 
    print_thousand(VALUE_HUNDRED_A); /* Want a compile error here */ 

    return 0; 
} 

回答

-1

我认为,这个问题是不是尽可能多的C不支持严格的类型检查,因为它是,它实际上并不支持真正的用户自定义类型。

我的猜测是,大多数C编译器会将你的枚举转化为简单的整数或短裤或其他任何东西,除此之外不会做任何事情。

所以据我所知,答案是知道的。

-1

单单C就没有办法做到这一点,因为编译器除了基本类型之外什么都不知道。通常情况下使用宏,但这是一个运行时检查。

0

你不能这样做。在C++中,你可以重载函数并做一些欺骗(或者使用boost :: enable_if),或者仅仅依靠C++的类型安全性,使其自动出错。在C中,这不起作用,因为不支持函数重载。而且你不能检查函数中的值并导致编译时错误,因为所有的值只在运行时才知道(与类型相反)。

C标准允许编译器警告你做什么。所以你可以启用-Wall -Werror标志,并希望gcc将会出错。但这不是一个通用的C方式。

10

在C中,枚举类型与整数无法区分。很烦人。

我能想到的唯一方法就是使用结构而不是枚举的工具。结构是有生命力的,所以成千上万是不同的。如果调用约定是合理的(AMD64),则不会有运行时间开销。

下面是一个使用结构的例子,它可以获得你想要的编译时错误。 Kludgy,但它的作品:

#include <stdio.h> 
enum hundred_e { 
    VALUE_HUNDRED_A = 100, 
    VALUE_HUNDRED_B 
}; 

enum thousand_e { 
    VALUE_THOUSAND_A = 1000, 
    VALUE_THOUSAND_B 
}; 

struct hundred { enum hundred_e n; }; 
struct thousand { enum thousand_e n; }; 

const struct hundred struct_hundred_a = { VALUE_HUNDRED_A }; 
const struct hundred struct_hundred_b = { VALUE_HUNDRED_B }; 
const struct thousand struct_thousand_a = { VALUE_THOUSAND_A }; 
const struct thousand struct_thousand_b = { VALUE_THOUSAND_B }; 

void print_hundred(struct hundred foo) 
{ 
    switch (foo.n) { 
     case VALUE_HUNDRED_A:  printf("hundred:a\n");  break; 
     case VALUE_HUNDRED_B:  printf("hundred:b\n");  break; 
     default: printf("hundred:error(%d)\n", foo.n); break; 
    } 
} 

void print_thousand(struct thousand bar) 
{ 
    switch (bar.n) { 
     case VALUE_THOUSAND_A:  printf("thousand:a\n");  break; 
     case VALUE_THOUSAND_B:  printf("thousand:b\n");  break; 
     default: printf("thousand:error(%d)\n", bar.n); break; 
    } 
} 

int main(void) 
{ 

    print_hundred(struct_hundred_a); 
    print_hundred(struct_thousand_a); /* Want a compile error here */ 

    print_thousand(struct_thousand_a); 
    print_thousand(struct_hundred_a); /* Want a compile error here */ 

    return 0; 
} 
0

我认为答案是严格的,“这取决于编译器”。我相当肯定代码是合法的C,所以默认情况下C编译器不会/不应该抱怨,但是在不同的编译器中可能有不同的选项可以选择它们。

如果这种类型的错误检查对您很重要,那么我建议您研究一下C linters/style checker/static分析工具,它可以捕捉到这个和其他常见错误(如果您正确设置它们) 。将这些工具添加到构建过程中是一项工作,但如果对于您的项目,您认为在编译时捕获这些类型的东西是有价值的,那么成本将是值得的。

两个,我会建议是:

FlexeLint,这是我已经习惯了很大的影响相对便宜的商业产品。

一个开源的替代方案是Splint,但不幸的是,它似乎目前大部分没有维护。

有更昂贵的商业工具,如Klocwork和Coverity。

将这些工具添加到您的软件需要付出一些努力。它们通常非常灵活且可定制,因此您需要就您希望允许的行为以及您希望在代码库中禁止的行为做出一些有教育的决定。

0

你可以使用#defines为你的函数和__builtin_constant(x),如果x解析为常量则返回1,否则返回0。注意这是一个仅限gcc的内在;我不知道其他编译器是否有等价物。