Как мне узнать, подписана ли целочисленная переменная C?

StackOverflow https://stackoverflow.com/questions/1412197

  •  05-07-2019
  •  | 
  •  

Вопрос

В качестве упражнения я хотел бы написать макрос, который сообщает мне, является ли целочисленная переменная подписанной. Это то, что у меня есть, и я получаю ожидаемые результаты, если попробую это с переменной char с помощью gcc -fsigned-char или -funsigned-char.

#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0) 

Это портативный? Есть ли способ сделать это, не разрушая значение переменной?

Это было полезно?

Решение

#define ISVARSIGNED(V)  ((V)<0 || (-V)<0 || (V-1)<0)

не меняет значение V. Третий тест обрабатывает случай, когда V == 0.

В моем компиляторе (gcc / cygwin) это работает для int и long, но не для char или short.

#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0)

также выполняет работу в двух тестах.

Другие советы

Если вы используете GCC, вы можете использовать ключевое слово typeof, чтобы не перезаписывать значение:

#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 })

При этом создается временная переменная _V того же типа, что и V.

Что касается переносимости, я не знаю. Он будет работать на машине комплимента для двоих (т.е. всего, на что ваш код когда-либо будет работать по всей вероятности), и я верю, что он будет работать и на машинах комплимента и знака и величины. В качестве дополнительного примечания: если вы используете -1, вы можете привести typeof (V) к <=>, чтобы сделать его более безопасным (то есть с меньшей вероятностью вызывать предупреждения).

#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0))

Без уничтожения значения переменной. Но не работает для 0 значений.

Как насчет

#define ISVARSIGNED(V) (((V)-(V)-1) < 0)

Другой подход ко всему & сделать его отрицательным " ответы:

#define ISVARSIGNED(V) (~(V^V)<0)

Таким образом, нет необходимости иметь особые случаи для разных значений V, так как & # 8704; V & # 8712; & # 8484 ;, V ^ V = 0.

Это простое решение не имеет побочных эффектов, в том числе преимущество только одной ссылки на v (что важно в макросе). Мы используем расширение gcc & Quot; typeof & Quot; чтобы получить тип v, а затем приведите -1 к этому типу:

#define IS_SIGNED_TYPE(v)   ((typeof(v))-1 <= 0)

Это < =, а не просто < чтобы избежать предупреждений компилятора в некоторых случаях (если включено).

С какой стати тебе нужен макрос? Шаблоны отлично подходят для этого:

template <typename T>
bool is_signed(T) {
    static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>");
    return std::numeric_limits<T>::is_signed;
}

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

РЕДАКТИРОВАТЬ . Ой, вопрос требует C. Тем не менее, шаблоны - хороший способ: P

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

#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1))
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0

Таким образом, в основном этот макрос использует условное выражение, чтобы определить, установлен ли старший бит числа. Если это не так, макрос устанавливает его путем побитового отрицания числа. Мы не можем сделать арифметическое отрицание, потому что -0 == 0. Затем мы сдвигаемся вправо на 1 бит и проверяем, произошло ли расширение знака.

Это предполагает арифметику дополнения 2, но обычно это безопасное предположение.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top