Сравнение C 'x <0', где тип 'x' произвольный, то есть может быть без знака - PullRequest
1 голос
/ 06 июня 2019

Дано:

Тип, определенный как TheValueT, который может быть произвольно сконфигурирован, например, как uint8_t или int64_. Пусть будет какой-то код:

TheValueT   x = ...;

... do something to 'x' ...

if( x < 0 ) {
   /* Do something. */
}

ПРОБЛЕМА:

Бывает, что если TheValueT определен как тип без знака, компилятор жалуется на «условие всегда истинно из-за ограниченного диапазона типа ...».

ВОПРОС:

Как можно избежать предупреждения компилятора, оставляя TheValueT произвольным целочисленным типом? Решение должно быть применимо к самому широкому спектру компиляторов C.

Ответы [ 3 ]

2 голосов
/ 06 июня 2019

Простой и безопасный способ написания вашего теста был бы следующим:

TheValueT x = /* ... */;

if (x < 1 && x != 0) {
    // do something
}

Возможно, достаточно умный компилятор предупредит об этом в любом случае, но то же самое верно для любой правильной альтернативы, которая можетбыть написано, чтобы охватить все возможные целочисленные типы (включая типы расширений).То, что работает , обходит предупреждение в моей реализации.

Нет альтернативы, требующей арифметических вычислений со значением x, во всех случаях определенно дает правильный результат - они сталкиваются с проблемами сзначения x в крайних диапазонах его или других типов.

Предполагается, что TheTypeT должен иметь тип integer .Если возможны и плавающие типы, то лучше всего просто жить с предупреждением или использовать флаг компилятора, чтобы отключить это конкретное предупреждение во время производственных сборок.

1 голос
/ 07 июня 2019

Вариация на тему .Работает и для FP.

if (x <= 0 && x != 0) {
1 голос
/ 06 июня 2019

Возможно решение Generic ?

#include <stdio.h>
#include <stdlib.h>

#define less_than_zero(x) _Generic((x) + 0, \
  int: (x) < 0, \
  long: (x) < 0, \
  long long: (x) < 0, \
  default: (x) * 0 \
  )

#if 1
int main(void) {
  short sh = -1;
  int i = -1;
  long long ll = -1;
  unsigned short us = -1u;
  unsigned u = -1u;
  unsigned long long ull = -1u;

  if (less_than_zero(sh)) puts("sh");
  if (less_than_zero(i)) puts("i");
  if (less_than_zero(ll)) puts("ll");
  if (less_than_zero(us)) puts("us");
  if (less_than_zero(u)) puts("u");
  if (less_than_zero(ull)) puts("ull");
  return 0;
}

Нет условие всегда истинно из-за ограниченного диапазона предупреждения типа .
Выход

sh
i
ll
...