Предотвращение смешивания перечисляемого типа с предупреждениями другого типа для логических значений в Keil uVision

Я переношу приложение, которое разрабатывал в CodeWarrior v5.2, на Keil uVision v5.25, в котором используется компилятор ARM C v5.06.

В моем коде я использовал bool для представления логических значений, которые определены в файле types.h в моем проекте как:

typedef enum _bool 
{ 
  false = 0, 
  true = 1 
} bool;

Когда я пытаюсь скомпилировать свой код, компилятор выдает предупреждения о строках, где я неявно присваиваю результат сравнений переменным с таким типом:

src\c\drivers\motor.c(168): warning:  #188-D: enumerated type mixed with another type
    const bool motorStopped = timeSinceLastEvent > maxPulseWidth;
src\c\drivers\motor.c(169): warning:  #188-D: enumerated type mixed with another type
    const bool motorStalled = motorStopped && isMotorDriven();

Я понимаю, почему эти предупреждения генерируются. Я знаю, что могу подавить эти предупреждения, явно приведя к bool, например:

const bool motorStopped = (bool)(timeSinceLastEvent > maxPulseWidth);

Однако делать это для каждого логического условия довольно некрасиво. Мне было интересно, есть ли способ настроить компилятор Keil uVision/ARM (или изменить мой код), чтобы он не генерировал предупреждения о bool, без прямого отключения предупреждений о смешивании перечислимых типов с другими типами.

Вот варианты, которые у меня есть для настройки компилятора:


person Tagc    schedule 18.07.2018    source источник
comment
Почему не typedef bool как int?   -  person Ctx    schedule 18.07.2018
comment
@Ctx Почему бы не использовать стандартный тип и макросы? Вы вообще не должны определять имена, которые являются частью стандартной библиотеки. Определение собственного bool может привести к нарушению стандартного совместимого кода.   -  person too honest for this site    schedule 18.07.2018
comment
@Ctx неплохая идея, в этом файле types.h также есть typedef unsigned char boolean; вместе с TRUE и FALSE. Переключение всех моих bool на boolean кажется лучшей идеей.   -  person Tagc    schedule 18.07.2018
comment
И не используйте пользовательские заголовки с тем же именем, что и стандартные заголовки. Ваш компилятор должен обеспечить хотя бы минимальный набор. Если types.h нет, возможно, на то есть причина. Если есть, то он должен работать с компилятором и соответствовать стандарту.   -  person too honest for this site    schedule 18.07.2018
comment
@Olaf Я этого не делал, это сторонний файл, поставляемый с комплектом SDK. Тип bool, определенный в этом файле, также используется во многих SDK, и если бы я использовал тип, определенный в stdbool.h, он бы затенил его. В противном случае я бы использовал stdbool.h.   -  person Tagc    schedule 18.07.2018
comment
Могу я спросить, почему за этот вопрос проголосовали?   -  person Tagc    schedule 18.07.2018
comment
Так что попросите производителя этой штуки сделать ее C-совместимой! Ни одна разумная компания не должна принимать нестандартный код C. Этот typedef может легко сломать другие части вашей (или, возможно, какой-то другой внешней библиотеки, которая совместима).   -  person too honest for this site    schedule 18.07.2018
comment
Для справки: это сторонний файл types.h, который включается в проект. hastebin.com/rocosaraji.c   -  person Tagc    schedule 18.07.2018
comment
1) мы не будем переходить по внешним ссылкам. 2) Вы убедились, что не нарушаете авторские права автора этого файла?   -  person too honest for this site    schedule 18.07.2018
comment
1) Если вы не хотите, это нормально — другие могут захотеть увидеть файл 2) Авторские права указаны в верхней части этого файла и говорят, что повторное распространение разрешено, если авторские права включены и не используются для одобрения.   -  person Tagc    schedule 18.07.2018
comment
@Olaf На самом деле, я думаю, я знаю, почему они сделали это таким образом - stdbool.h недоступен в C89, и поэтому они, возможно, сами определили его, чтобы тип bool был доступен независимо от того, какой стандарт C используется. Я определил подобное перечисление, когда работал с другим микро с CodeWarrior 5.2 и был вынужден использовать C89.   -  person Tagc    schedule 18.07.2018
comment
C89 не является стандартным C. И он скомпилирован как C99 (тоже нестандартный, но, возможно, лучший, который вы получаете с проприетарными коммерческими компиляторами).   -  person too honest for this site    schedule 18.07.2018


Ответы (2)


Это казалось грязным, но я решил эту проблему, изменив файл types.h, поставляемый с комплектом SDK, включив в него stdbool.h вместо определения собственного типа bool. Перекомпиляция моего проекта не вызвала предупреждений/ошибок ни в стороннем коде, который использовал bool, ни в моем собственном коде.

На всякий случай я попытался изменить его таким образом, чтобы он все еще работал, если он был скомпилирован в проекте C89:

#if __STDC_VERSION__ >= 199901L
#include <stdbool.h>
#endif

// ...

#if __STDC_VERSION__ < 199901L
typedef enum _bool 
{ 
  false = 0, 
  true = 1 
} bool;
#endif
person Tagc    schedule 18.07.2018

Во-первых, такого рода определения логически некорректны в C.

C определяет false как ноль, а true как не ноль, что, конечно, включает 1, но не только это. Это может быть опасно во многих ситуациях:

Выражение if(GetValue() == true) оценивается как истинное только в том случае, если возвращаемое значение функции равно 1. Это чрезвычайно опасно и может быть источником многих трудно обнаруживаемых ошибок.

bool может иметь любое значение, поскольку за ним стоит int.

Кастинг ничего не меняет:

#include <stdio.h>
#include <string.h>

typedef enum _bool 
{ 
  false = 0, 
  true = 1 
} bool;

int main(void) {

    bool x;

    x = 50;
    printf("%d\n", x);

    x = (bool)50;
    printf("%d\n", x);
}

https://ideone.com/nNHPLg

Вы будете явно преобразовывать значения int в нули или единицы. Например:

bool x = !!something;

bool x = something ? true : false;

person 0___________    schedule 18.07.2018
comment
В соответствии со стандартом true — это макрос, который заменяется на целочисленную константу 1 типа int. с false по 0. Итак, true это на самом деле 1, а не не 0. Вы путаете макросы и стандартный тип _Bool с тем, как результат условия интерпретируется составными операторами, соответственно. условный оператор. И код, который вы показываете, ясно дает понять, чтоs wrong with the typedef. (bool)50 оценивается как 1 в соответствии со стандартом. Он может **представлять только значения 0 и 1. - person too honest for this site; 18.07.2018
comment
Наконец: базовый тип для enum не обязательно будет int. Константы-перечисления имеют тип int, но объект типа enum не обязательно. Реализация может выбрать меньший тип. Это одна из основных проблем с enums в C. В результате такой объект может быть не в состоянии содержать все значения, которые int может содержать. - person too honest for this site; 18.07.2018
comment
@Olaf - да, но наименьший тип int - это char, который может вместить более 0 и только один. Базовый тип является одним из целочисленных типов. Стандарт говорит, что любое ненулевое значение считается истинным, только результаты логических операций гарантированно будут 0 или 1. - person 0___________; 18.07.2018
comment
@Olaf IMO определение типа bool имеет смысл только в языках, которые не допускают неявных преобразований типов (например, C++). В противном случае сравнение с true может дать неправильные результаты, как в моем ответе. - person 0___________; 18.07.2018
comment
@Olaf - и, наконец, я отвечаю на конкретный вопрос, где он определяется так, как он определен (это не тип bool из stdint.h) - person 0___________; 18.07.2018
comment
Код соответствует C99, что делает мои возражения обоснованными. И char — это целочисленный тип txype, а не int. В программировании и особенно для начинающих мы должны быть точными. Вы написали, что bool может иметь любое значение, поскольку за ним стоит int. который я исправил, поскольку это просто неправильно заявил этот генерал. И определение bool вообще не имеет смысла, поскольку C99+ имеет логический тип, а bool, как указано в стандарте, имеет другие последствия, чем enum или любой другой стандартный тип (поэтому он был добавлен). Попробуйте _Bool b = 50;! - person too honest for this site; 18.07.2018
comment
@ Олаф, это придирки. Встроенные логические типы генерируют совершенно другой код, чем это перечисление. А те в данном вопросе не учитываются. Сосредоточьтесь на вопросе, а не на общих рассуждениях не по теме. Вопрос о типе enum, определяемом OP. Определять логический тип таким образом в C — очень плохая идея. - person 0___________; 18.07.2018
comment
Судя по всему, OP сфокусировался на вопросе и моих комментариях. Смотрите его ответ, он действительно использовал стандартный способ. Возможно, я выгнал продавца, но мы не знаем подробностей. В конце концов, его способ может сломать только библиотеку (менее вероятно, если только она полностью не испорчена), а не приложение или совместимый код. Забавно: Ваше последнее предложение почти то же самое, что я написал вначале… - person too honest for this site; 18.07.2018
comment
@ Олаф, мой ответ об этом. Почему он не должен делать это таким или подобным образом. - person 0___________; 18.07.2018