Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force compile error if function argument out of range

Tags:

c

I am restricted to C (cannot use C++). I wish C had stricter type checking.

Is there a way to get compile errors on the commented lines? If it helps, the enum values cannot overlap.


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;
}
like image 333
Henry Avatar asked Nov 27 '25 22:11

Henry


1 Answers

In C, enum types are indistinguishable from integers. Very annoying.

The only way forward I can think of is a kludgy workaround using structs instead of enums. Structs are generative, so the hundreds and thousands are distinct. If the calling convention is sensible (AMD64) there will be no run-time overhead.

Here's an example using structs that gets the compile-time errors you wanted. Kludgy, but it works:

#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;
}
like image 86
Norman Ramsey Avatar answered Nov 30 '25 10:11

Norman Ramsey



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!