LINUX.ORG.RU
ФорумTalks

[си/си++]почему так? ошибка в gcc? проверьте, пжл, на 64 бит


0

0

[andrey@workstation tmp]$ cat test.cpp
#include <iostream>

int main() {
unsigned int x1 = 3, x2 = 4;
long x3 = 0;
x3 = (static_cast<long>(x1 - x2)) >> 1;
std::cerr<<"x1: "<<x1<<", x2: "<<x2<<", x3: "<<x3<<std::endl;
return 0;
}

компиляем

[andrey@workstation tmp]$ g++ -o t test.cpp

результат на 32 битной машине

[andrey@workstation tmp]$ ./t
x1: 3, x2: 4, x3: -1

результат на 64 битной машине

[admin@blingeasy2 t3]$ ./t
x1: 3, x2: 4, x3: 2147483647


вопроса 2, собственно:

1) что же происходит?

2) может ли кто нить проверить на 64 битной машине с другой версией гсс пжл.

gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44)


★★★★★

Многострочник на СИ ? =)

arknir
()

Я заранее извиняюсь, но сейчас задам глупый вопрос: чем
x3 = (static_cast<long>(x1 - x2)) >> 1;
отличаеся от
x3 = (long)(x1 - x2);
И что вообще даёт " >> 1"?

P.S. Да, плюсы я фактически вообще не знаю, в некоторой степени лишь знаком с си.

Ramen ★★★★
()

1) на 64 битной машине инты в 4 байта пишутся, лонги в 8 байт.

2) если вы в целочисленных интах сделали -1 (все выставили в 1) в интах это всё ещё много (но никак не -1).

т.е. что мы имеем: при переводе из целочисленного 2 мильёна в лонг (но знаковый и той же 4-байтной длины) получаем знаковое представление 2х мильёнов

при переводе 2х мильёнов целочисленных в 8-байтный знгаковый лонг ничего никуда не теряется...

вопрос в представлении чилес

gunja
()

> x3 = (static_cast<long>(x1 - x2)) >> 1;

у тебя вычитаются два unsigned int, при этом результат будет тоже - unisnged int - потом ты его конвертишь в long: (x1 - x2) - тип результата будет типом первого операнда.

Т.е. логичнее было бы делать так:

x3 = (long(x1) - x2) >> 1;

Spectr ★★★
()
Ответ на: комментарий от Ramen

>И что вообще даёт " >> 1"?

Битовый сдвиг вправо на 1 бит.

tzukko
()
Ответ на: комментарий от Ramen

> Я заранее извиняюсь, но сейчас задам глупый вопрос: чем > x3 = (static_cast<long>(x1 - x2)) >> 1; > отличаеся от > x3 = (long)(x1 - x2); > И что вообще даёт " >> 1"?

Мне тоже очень непонятно зачем там >> 1. Может кто пояснит.

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от sig_wall

ага, я понял. А зачем там вообще >> 1?

AndreyKl ★★★★★
() автор топика

поясню. код не мой. из ImageMagick. файл Magick++/lib/Image.cpp

там таким образом (вместо того, чтобы просто отнять и привести к типу) вычисляюстя координаты.

Кто нибудь, просветите неграмотного, зачем может быть нужен в такой ситуации >> 1 ?

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от gunja

> статик каст это и есть С-подобное приведение типа

для Си'шного приведения типа в общем случае нет Си++'ого аналога.

Reset ★★★★★
()

без сдвига на 32 битной машине работает верно (что ожидаемо), а на 64 битной получается число в два раза больше (что тоже ожидаемо). Зачем там сдвиг??

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от sig_wall

> 0x00000000ffffffff sar 1 = 0x000000000fffffff = 2147483647

Тут кстати, что-то не так..

по моему, должно быть так

0х0000ffff sar 1 = 0x00008fff

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от AndreyKl

> Зачем там сдвиг?

самое простое решение - так можно понять разрядность системы (один из косвенных признаков).

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

gunja
()
Ответ на: комментарий от AndreyKl

> ага, я понял, спасибо. теперь вопрос зачем там >> 1

ну вообще это аналог деления на два (с положительными числами), но похоже с отрицательными числами он себя ведет странно :-O

-4 >> 1 == -2
-3 >> 1 == -2
-2 >> 1 == -1
-1 >> 1 == -1
0 >> 1 == 0
1 >> 1 == 0
2 >> 1 == 1
3 >> 1 == 1
4 >> 1 == 2

Spectr ★★★
()
Ответ на: комментарий от AndreyKl

написан он в самом деле несколько не верно. но конечная цифра правильная. все ф-ки и будет 4 миллиарда с чем-то минус 1.

по поводу сдвига читайте

http://wiki.pcmag.ru/index.php?title=%D0%91%D0%B8%D1%82%D0%BE%D0%B2%D1%8B%D0%...

арифметический сдвиг (лонг - знаковый).

gunja
()
Ответ на: комментарий от Reset

> для Си'шного приведения типа в общем случае нет Си++'ого аналога.

почему нет? Описан же четкий алгоритм, как определить что Сишный каст означает -- const_cast, static_cast либо reinterpret_cast.

dilmah ★★★★★
()
Ответ на: комментарий от gunja

код запросто:

{

long x = 0; long y = 0;

x = static_cast<long>(columns() - compositeImage_.columns()) >> 1; y = static_cast<long>(rows() - compositeImage_.rows()) >> 1;

вызов_функции_от_x_y(x, y);

}

комментариев инкаких.

columns() и rows() возвращают unsigned int.

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от AndreyKl

так это можно смело делением на два заменять - извратное поведение сдвига при отрицательных числах погоды не сделает, раз у тебя середина позиций берется - ошибка будет +-0.5 в любом случае

Spectr ★★★
()
Ответ на: комментарий от AndreyKl

да, деление на 2, это точно. потому что вычисляется центр. как сам не догадался...

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от dilmah

В том то и дело, что () это комбинация различных *_cast'ов.

Reset ★★★★★
()

всем спасибо

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от AndreyKl

> код запросто

есть сильное подозрение, что тогда, когда писали этот код _очень_сильно_ заложились на то, что инты и лонги одного размера (заложились на 32-х рязрядную архитектуру).

gunja
()
Ответ на: комментарий от AndreyKl

я могу и ошибаться... но есть подозрение, что это не совсем сработает.

я бы настаивал на приведении каждого беззнакового сначала в лонг (или хотя бы одного из них) и только потом выполнял операции потенциально приводящие к знаковому результату.

\\найденную ошибку с -1 в беззнаковых интах переведённых в больший лонг (т.е. в 4 млрда) и последующее деление на 2 не исправит просто замена сдвига на деление.

но могу и ощибаться

gunja
()
Ответ на: комментарий от AndreyKl

> теперь вопрос зачем там >> 1

ну вообще это быстрый способ деление на степень двойки (в коде magick находится середина стороны).

sig_wall
()
Ответ на: комментарий от AndreyKl

> пошёл заменять делением на два. спасибо.

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

Т.е. лучше оставить как есть, либо убедится на тестах, что это не критично. Сорри :)

Spectr ★★★
()
Ответ на: комментарий от gunja

да, всё верно, сначала надо привести оба, потом сдвигать.

в общем заменить выражение надо на

x3 = (static_cast<long>(x1) - static_cast<long>(x2))>>1;

так вроде правильный результат и на 32 битах и на 64.

Всем спасибо, пойду патчи запощу.

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от sig_wall

Да, я понял.. мог бы и сам догадаться...

спасибо.

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от Spectr

да не, там просто ищут середину отрезка, побочных эффектов быть не должно. Хотя я оставил как было практически..

AndreyKl ★★★★★
() автор топика
Ответ на: комментарий от Spectr

-4 >> 1 == -2 -3 >> 1 == -2 -2 >> 1 == -1 -1 >> 1 == -1 0 >> 1 == 0 1 >> 1 == 0 2 >> 1 == 1 3 >> 1 == 1 4 >> 1 == 2

-4 / 2 == -2 -3 / 2 == -1 -2 / 2 == -1 -1 / 2 == 0 0 / 2 == 0 1 / 2 == 0 2 / 2 == 1 3 / 2 == 1 4 / 2 == 2

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

Spectr ★★★
()
Ответ на: комментарий от AndreyKl

>>ага, я понял, спасибо. теперь вопрос зачем там >> 1

оптимизированное целочисленное деление на 2?

exception13 ★★★★★
()
Ответ на: комментарий от AndreyKl

> по моему, должно быть так

да, ошибся, там 0x000000007fffffff.

sig_wall
()
Ответ на: комментарий от AndreyKl

> так вроде правильный результат и на 32 битах и на 64

к сожалению не всегда.

ситуация: одна координата больше 2^31 вторая меньше но всё ещё большая сама по себе (помним, что они целочисленные).

при переводе каждой из них в знаковые лонги на 32-х разрядной машине, получае отрицательное число (старший бит в целочисленном был равен 1) и большое число (меньше 2^31 но большое). получаем отрицательное минус положительное - большое отрицательное. никак не что-то положительное (что ожидалось при вычитании целочисленных).

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

gunja
()
Ответ на: комментарий от AndreyKl

>Мне тоже очень непонятно зачем там >> 1. Может кто пояснит.
>А зачем там вообще >> 1?

>Кто нибудь, просветите неграмотного, зачем может быть нужен в такой ситуации >> 1 ?

>теперь вопрос зачем там >> 1

Идущие подряд 4 поста с процитированными выше фрагментами - это сильно. (:

Ramen ★★★★
()
Ответ на: комментарий от Spectr

>-3 >> 1 == -2
>3 >> 1 == 1


это скорее всего от того, что floor(-1.5) = -2 floor(1.5) = 1

dimon555 ★★★★★
()

Есть возможность заменить все лонги в проекте на int? Просто вся жопа в данном случае из-за того, что применяются разные типы данных, имевшие когда-то один размер. Меньше разнообразие типов - меньше потенциальных косяков там, где ты их еще не нашел.

YesSSS ★★★
()
Ответ на: комментарий от AndreyKl

> x3 = (static_cast<long>(x1) - static_cast<long>(x2))>>1;

Заменять деление побитовым сдвигом компиляторы научились еще в прошлом тысячелетии. Так что для улучшения читабельности лучше всё же писать х/2 и не париться.

Relan ★★★★★
()
Ответ на: комментарий от anonymous2

мы не забыли даже патч засабмитить. А баг отправили недели две назад. До сих пор ответа нет. Проще оказалось самому пол часа потратить и на ЛОРе пол часа пофлеймить, чем ждать у моря погоды/ответа разработчиков.

AndreyKl ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.