Принудительная ошибка компиляции, если аргумент функции находится вне диапазона - PullRequest
3 голосов
/ 13 декабря 2008

Я ограничен 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 ]

10 голосов
/ 13 декабря 2008

В C типы enum неотличимы от целых чисел. Очень раздражает.

Единственный способ продвинуться вперед, о котором я могу думать, - это хитрый обходной путь, использующий структуры вместо перечислений. Структуры являются генеративными, поэтому сотни и тысячи различны. Если соглашение о вызовах разумно (AMD64), не будет никаких накладных расходов во время выполнения.

Вот пример использования структур, которые получают ошибки времени компиляции, которые вы хотели. Клудги, но работает:

#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 голосов
/ 14 декабря 2008

Вы можете сделать это, используя #defines для ваших функций и __builtin_constant (x), который возвращает 1, если x разрешает константу, и 0, если нет. Обратите внимание, что это только встроенная функция gcc; Я понятия не имею, есть ли эквиваленты на других компиляторах.

0 голосов
/ 14 декабря 2008

Я думаю, что строго ответ: «это зависит от компилятора». Я вполне уверен, что код является допустимым C, поэтому по умолчанию компилятор C не будет / не должен жаловаться, но, возможно, в разных компиляторах есть разные варианты, которые могут его поднять.

Если этот тип проверки ошибок важен для вас, тогда я предлагаю исследовать С-линтеры / средства проверки стиля / инструменты статического анализа, которые улавливают эту и другие распространенные (и не очень) ошибки (если вы их правильно настроили!). Добавление этих инструментов в процесс сборки - это небольшая работа, но если для вашего проекта вы считаете, что перехват такого рода вещей при компиляции является ценным, тогда стоимость того стоит.

Два я бы порекомендовал:

FlexeLint , который является относительно недорогим коммерческим продуктом, который я использовал с большим эффектом.

Альтернативой с открытым исходным кодом будет Splint , но, к сожалению, на данный момент она в основном не поддерживается.

Существуют более дорогие коммерческие инструменты, такие как Klocwork и Coverity.

Добавление таких инструментов в ваше программное обеспечение требует определенных усилий. Они, как правило, чрезвычайно гибкие и настраиваемые, и вам необходимо принять некоторые обоснованные решения о том, какое поведение вы хотите разрешить, а какие - запретить в своей базе кода.

0 голосов
/ 13 декабря 2008

Вы не можете сделать это. В C ++ вы можете перегружать функцию и делать некоторые хитрости (или использовать boost :: enable_if), или просто полагаться на безопасность типов в C ++, делая ее автоматически ошибочной. В C это не работает, поскольку перегрузка функций не поддерживается. И вы не можете проверить значение в функции и вызвать ошибку времени компиляции, так как все значения известны только во время выполнения (в отличие от типов).

Стандарт C позволяет компиляторам предупреждать о том, что вы делаете. Таким образом, вы можете включить флаг -Wall -Werror и надеяться, что gcc выдаст ошибку. Но это не общий способ C.

0 голосов
/ 13 декабря 2008

Нет никакого способа, которым один C мог бы сделать это, потому что компилятор не знает ничего, кроме базовых типов. Обычно используется макрос assert(), но это проверка во время выполнения.

0 голосов
/ 13 декабря 2008

Я бы сказал, что проблема не в том, что C не поддерживает строгую проверку типов, а в том, что он действительно не поддерживает настоящие определяемые пользователем типы.

Я предполагаю, что большинство компиляторов Си будут переводить оба ваших перечисления в простые целые числа или шорты или что-то еще и не будут делать ничего кроме этого.

Так что, насколько я могу судить, ответ будет знать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...