2008-12-13 6 views
3

Je suis limité à C (impossible d'utiliser C++). Je souhaite que C ait une vérification de type plus stricte.Force l'erreur de compilation si l'argument de la fonction est hors plage

Existe-t-il un moyen d'obtenir des erreurs de compilation sur les lignes commentées? Si cela aide, les valeurs enum ne peuvent pas se chevaucher.


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; 
} 

Répondre

-1

Je dirais que le problème est pas autant que C ne supporte pas une vérification stricte de type, car il est vraiment qu'il ne supporte pas les vrais types définis par l'utilisateur. J'imagine que la plupart des compilateurs C traduiraient vos deux enums en simples ou courts métrages ou quoi que ce soit, et ne feraient rien d'autre que cela.

Donc pour autant que je peux dire, la réponse serait savoir.

-1

Il n'y a aucun moyen que C seul puisse le faire car le compilateur ne connaît rien d'autre que les types de base. La chose habituelle est d'utiliser la macro assert(), mais c'est une vérification de l'exécution.

0

Vous ne pouvez pas le faire. En C++, vous pourriez surcharger la fonction et faire un peu de supercherie (ou utiliser boost :: enable_if), ou simplement compter sur la sécurité de type C++, ce qui fait automatiquement sortir l'erreur. En C, cela ne fonctionne pas car la surcharge de la fonction n'est pas supportée. Et vous ne pouvez pas vérifier la valeur dans la fonction et provoquer une erreur de compilation, car toutes les valeurs sont connues uniquement au moment de l'exécution (par opposition aux types).

Le standard C permet aux compilateurs de vous avertir de ce que vous faites. Vous pouvez donc activer le drapeau -Wall -Werror et espérer que gcc va faire une erreur. Mais ce n'est pas un objectif général C.

10

En C, les types enum sont indiscernables des entiers. Très ennuyant.

La seule solution que je puisse imaginer est une solution de contournement kludgy utilisant des structures plutôt que des énumérations. Les structures sont génératives, donc les centaines et les milliers sont distincts. Si la convention d'appel est sensible (AMD64), il n'y aura pas de surcharge au moment de l'exécution.

Voici un exemple utilisant des structures qui obtiennent les erreurs de compilation que vous vouliez. Kludgy, mais cela fonctionne:

#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

Je pense strictement la réponse est, "cela dépend du compilateur". Je suis assez sûr que le code est C légal, donc par défaut un compilateur C ne devrait pas/ne devrait pas se plaindre, mais il y a probablement différentes options dans différents compilateurs qui peuvent le ramasser. Si ce type de vérification d'erreur est important pour vous, alors je suggère d'étudier C linters/style checkers/outils d'analyse statique qui attraperont cette erreur et d'autres communes (et pas si commun) erreurs (si vous les configurez correctement!) . C'est un peu de travail d'ajouter ces outils dans votre processus de construction, mais si pour votre projet, vous pensez que l'acquisition de ce genre de choses à la compilation est utile, alors le coût en vaudra la peine.

Deux Je recommande sont:

FlexeLint, qui est un produit commercial relativement peu coûteux que je l'ai utilisé à bon escient.

Une alternative open source serait Splint, mais malheureusement, il semble être pour la plupart non maintenu pour le moment.

Il existe des outils commerciaux plus coûteux tels que Klocwork et Coverity. L'ajout de ce type d'outils à votre logiciel demande un certain effort. Ils sont généralement extrêmement flexibles et personnalisables, et vous devez prendre des décisions éclairées sur les comportements que vous souhaitez autoriser, et que vous voulez interdire dans votre base de code.

0

Vous pouvez le faire en utilisant #defines pour vos fonctions et __builtin_constant (x), qui renvoie 1 si x se résout en une constante et 0 si ce n'est pas le cas. Notez que ceci est un intrinsèque de gcc seulement; Je n'ai aucune idée s'il y a des équivalents sur d'autres compilateurs.

Questions connexes