如果函数参数超出范围,则强制编译错误

时间:2008-12-13 03:21:38

标签: c

我被限制为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;
}

6 个答案:

答案 0 :(得分:10)

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

我能想到的唯一前进方法是使用结构而不是枚举的kludgy解决方法。结构是生成性的,因此数以千计是截然不同的。如果调用约定合理(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;
}

答案 1 :(得分:0)

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

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

我建议的两个是:

FlexeLint,这是一种相对便宜的商业产品,我已经习惯了很好的效果。

开源替代方案是Splint,但不幸的是,它目前似乎基本上没有维护。

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

将这些工具添加到您的软件确实需要一些努力。它们通常非常灵活且可自定义,您需要对要允许的行为以及您希望在代码库中禁用哪些行为做出一些明智的决定。

答案 2 :(得分:0)

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

答案 3 :(得分:0)

你不能这样做。在C ++中,您可以重载函数并执行一些技巧(或使用boost :: enable_if),或者仅依靠C ++的类型安全性使其自动出错。在C中,由于不支持函数重载,因此不起作用。并且您无法检查函数中的值并导致编译时错误,因为所有值仅在运行时已知(而不是类型)。

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

答案 4 :(得分:-1)

我认为问题并不像C不支持严格类型检查那么多,因为它确实不支持真正的用户定义类型。

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

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

答案 5 :(得分:-1)

单独C无法做到这一点,因为编译器除了基类型之外什么都不知道。通常情况下使用assert()宏,但这是运行时检查。