2008-12-13 48 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的內在;我不知道其他編譯器是否有等價物。