2013-12-01 3 views
1

я следующий код:Где происходит преобразование знака?

unsigned int x, last_x; 
int dx; 
[...] 
dx = x - last_x; 

Компиляция это с г ++ (4.7.2) и -Wsign-преобразования производит следующее: warning: conversion to ‘int’ from ‘unsigned int’ may change the sign of the result [-Wsign-conversion]

Единственный способ сделать предупреждение исчезает, изменив чтобы:

dx = static_cast<int>(x) - static_cast<int>(last_x); 

или

dx = static_cast<int>(x - last_x); 

Какое объяснение этого поведения? Является ли оператор - определенным для подписанных ints? Я ожидаю, что будет иметь оператор -, который принимает значения без знака и возвращает значение со знаком.

+0

Я не могу воспроизвести это с GCC 4.8.2, который GCC версии сделал у ou использовать? – nos

+0

Я использую 4.7.2 –

+0

Первый литой (static_cast (x - last_x)) не дает предупреждения (g ++ (Ubuntu/Linaro 4.7.2-2ubuntu1) 4.7.2) –

ответ

2

Операции на unsigned int s приведут к unsigned int s. Даже вычитание даст unsigned int. значение просто обертывается: в отличие от целочисленной арифметики со знаком, переполнение и недополнение для значений без знака приводит к правильному определению поведения: арифметика - это просто модуль N, где N является одним плюс максимальное значение, которое может быть представлено целым числом без знака.

+0

Так что, если я правильно понимаю, тип 'x - last_x' является unsigned int? Почему не работает' static_cast (x - last_x) '? –

+0

Моя ошибка, кажется, что' static_cast'ing все выражение действительно работает. –

+0

@DanNestor: ну, если 'x (...)' явно, но это решение вплоть до исполнителей компилятора. –

1

Компилятор предупреждает вас, что введенное вами заявление, dx = x - last_x;, может привести к непреднамеренному изменению знака. Это означает, что при выполнении x - last_x, который будет положительным числом, когда вы конвертируете его в int и сохраните его в dx, это значение может стать отрицательным.

Рассмотрите возможность изменения unsigned int x, last_x; на int x, last_x;.

+0

изменение на (int) (x - last_x) делает * not * удаляет предупреждение. –

+0

Кроме того, dx не может быть изменен на unsigned. Рассмотрим, что x и last_x представляют координаты, а dx разрешено быть отрицательным. –

+0

@DanNestor Вы абсолютно правы. Я изменил свой ответ. –

0

Поскольку вы имеете дело с unsigned целыми числами, вы должны принять меры предосторожности при вычитании, чтобы избежать отрицательных результатов:

if (x > last_x) 
{ 
    dx = x - last_x; 
} 
else 
{ 
    dx = last_x - x; 
} 

Как уже говорилось, отрицательный результат может вызвать наматывается вокруг.

Edit 1:
Если вы хотите dx быть подписан результат, вы должны отбрасывать другие значения signed int Перед вычитанием:
dx = (signed int)x - (signed int) last_x;

0

Предупреждение пытается предупредить вас, что все может пойти неправильно! Рассмотрим:

unsigned int x = UINT_MAX; 
unsigned int last_x = 0; 

int dx = x - last_x; 

Очевидно разница UINT_MAX, но это не вписывается в междунар, так что вы получите (предположительно нежелательный) результат -1.

Единственный раз, когда это будет работать как задумано, если x является частью циклической последовательности (например, часы опрокидывание), в этом случае вы должны использовать

int dx = static_cast<int>(x - last_x); 

Но не

int dx = static_cast<int>(x) - static_cast<int>(last_x); 

как это может вызвать переполнение целочисленного - неопределенное поведение

Смежные вопросы