Имеем код: Код (Text): class C{ public: C(DWORD id): id(id) {}; __forceinline operator DWORD&(); DWORD id; }; DWORD dw; __forceinline C::operator DWORD &() { dw = id; return dw; } void main() { C a(1); C b(2); printf("%i %i", (DWORD)a, (DWORD)b); } Под VC7.1 в конфигурации debug получаем на выходе 1 2 Release - 1 1 Вопрос: Чей это глюк и где он?
глюк в шаловливых руках. sequence points при расчёте аргументов printf нету, студия в релизе их сначала сосчитала, а потом только распечатала. Есс-но второй вызов C::operator(DWORD) похерил глобальную переменную. кроме того, чтобы метод класса инлайнился, достаточно его описать внутри класса, не вынося наружу. И не надо будет всяких __forceinline Итог: студия всё корректно делает. А вот автор специально этого эффекта добивался. Зачем ?
Можно подробнее? Оператор приведения типа выдаёт ссылку на глобальную переменную, причём переменная меняется... так почему в релизе она не изменилась? По замыслу, printf("%i %i", (DWORD)a, (DWORD)b); эквивалентно printf("%i %i", dw=a.id, dw=b.id); Что такое sequence points?
scf Не надо далеко ходить. Достаточно: int i = 0; printf("%d%d%d%d", ++i, ++i, i++, i++); Скомпили в дебаге и релизе. Увидешь разницу.
debug:4410 release:2200 Помнится, в Сях выражения вычисляются справа налево... Кто-нибудь может объяснить этот эффект?
2vito: ерунду говоришь. Родной, ну где ты там баг увидел ? Приоритет определяет расстановку скобок в выражении. Что означает — какие операнды будут отданы какой функции/оператору. Ассоциативность действует для встроенных типов: оптимизирующий компилятор может подшаманить в выражении, чтобы, например, просуммировать все константы 1 + x() + 2 == (1+2) + x() Порядок вычислений в выражении — implementation-defined, и зависит от настроек оптимизации компилятора. (Понятно, что зависимые подвыражения вычислятся позднее, чем их аргументы). Например, в f( g1(), g2(), h( g3(), g4(), t( g5() ) ) ) порядок вызовов g1()...g5() произволен. x1 = g1(); x2 = g2(); x3 = g3(); x4 = g4(); y34 = h(x3,x4); x5 = g5(); y5 = t(x5); z = f(x1,x2,x3,x4,x5); (найти все вариации оставляю тем, кому делать нечего). Это касается и операторов, как встроенных, так и перекрытых.
компилятор выбирает способ вычисления аргументов ф-ции, исходя из предположения, что вычисления каждого аргумента взаимно независимы. Поэтому ни о каком порядке вычисления аргументов в оптимизированном коде говорить не приходится: может быть вычислена часть арг1, потом часть арг2, потом сл. часть арг1 и т.д. Исключение составляют лог. ф-ции(операторы) &&, ||. ДЛя них порядок вычисления определён.
screw Ну что ты так разволновался Вопрос толко один. Почему МS и Intel по разному воспринимают аналогичиный код? Причем второй корректно? ( при равнозначных опциях компилятора) Насчет корректности вопрос конечно относительный - будем понимать, то что мы логически хотели бы получить. Значит у Intel'а Порядок вычислений в выражении - не произволен? Вот недавно доделал проект и релиз перекомпилил под Intel, тот выплюнул сразу две ошибки, т.е. действительно ошибки, которые MS спокойно глотал? Гм... особенность реализации? З.Ы.То что автор намеренно добивался такого результата понятно. Действително принципиалных ошибок компилятора здесь нет, вопрос в различнях компиляторов. И соответственно вопрос в корректности.
infern0 ...главная проблема всех программ - они делают то что написано а не то что хотелось программисту... Сильно сказано)
а вот мне всё равно не до конца ясно... Проблема ведь в чём, как мне кажется. Что C, что C++, априори считает что произвольная функция не является pure. То есть она меняет контекст вычисления. Следовательно если есть два вызова функций в выражении, то их следует считать зависимыми, если конечно при объявлении этих функций не использовалось активно слово const. Или атрибут pure в gcc, или ещё что-нить в этом роде в vc++. А если они зависимы -- то неплохо было бы, если бы компилятор ругнулся. И на пример _DEN_'а gcc ругается, причём трижды (правда этот пример -- стандартный баг C). А на пример scf -- gcc не реагирует -- молчит собака. как я понял и vc++ и intel'овский компиляторы -- тоже. screw эта фраза про порядок вычисления... а если я напишу 'foo() + bar()' -- тоже порядок вызовов не определён? Не может быть. По-моему так (вроде я гдето читал такое, а может мне приснилось): операнды считаются слева направо (a() + b() + c()) или справа-налево (a() = b() = c()), а перестановки оптимизации ради, делаются только в случае когда компилятор _точно_ знает что это не изменит результата. Например, в твоём примере '1+x()+2'. Можно и в примере 'foo() + bar()', _если_ хотя бы одна из них объявлена как: 'int foo () const;', или компилятор достаточно продвинут, чтобы сообразить это самостоятельно.
если ты в том выражении напишешь ++i + ++i + i++ + i++ результат тоже будет определен. А оператор запятая не имеет жестко заданного порядка и определяется самими компилятором.
infern0 оператор запятая имеет жестко заданый порядок вычисления подвыражений - слева направо. А запятая, разделяющая параметры функции - это не оператор и здесь порядок вычисления не определен (точнее определяется реализацией).