On-line: гостей 0. Всего: 0 [подробнее..]
Программисты всех стран, объединяйтесь!

АвторСообщение



ссылка на сообщение  Отправлено: 28.07.12 21:31. Заголовок: MS VC++ 2010: баг компилятора - глобальная переменная скрывает имя метки для goto предложения


В процессе обсужения одного заковыристого и настолько же бесполезного с практической точки зрения кода обнаружил очередной баг компилятора MS VC++ 2010.

Этот баг связан с метками. Я его бы никогда не обнаружил, если бы не представившийся случай с обсуждением упомянутого кода, так как я сам никогда и ни при каких обстоятельствах не использую goto предложение. Для меня программист, который использует goto, это не программист, а недоучившийся студент.

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

Вот демонстрационный код этого бага


 #include "stdafx.h" 

struct A {};

int _tmain(int argc, _TCHAR* argv[])
{
A:
{
goto A;
}

return 0;
}


Компилятор на предложении goto выдает следующее сообщение об ошибке:


 цитата:
error C2226: синтаксическая ошибка: непредвиденный тип "A"



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

Спасибо: 0 
ПрофильЦитата Ответить
Ответов - 9 [только новые]





ссылка на сообщение  Отправлено: 28.07.12 21:32. Заголовок: Хотел бы добавить ва..


Хотел бы добавить важную информацию из стандарта С++ относительно меток. Метки имеют свое собственное пространство имен, а потому не конфликтуют с другими идентификаторами. Фактически, я пересказал следующую цитату из стандарта С++:


 цитата:
Labels have their own name space and do not interfere with other identifiers.



Об этом обычно как-то забывают программисты С++. Но если им придется столкнуться с описанным здесь багом,MS VC++, то очень кстати будет вспомнить про эту выдержку из стнадарта.

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 21:33. Заголовок: Вот еще один баг ком..


Вот еще один баг компилятора MS VC++ 2010, связанный с метками и оператором goto.

Согласно стандарту С++ можно передавать управление в область видимости переменной с автоматической памятью после ее объявления, если она не инициализируется. Но можно это делать, только если речь идет о переменных скалярных типов, или переменных имеющих тип класса при условии, что в этом классе имеется тривиальный конструктор по умолчанию и тривиальный деструктор. Вот выдержка описания такой возможности из стандарта из параграфа № 3 раздела "6.7 Declaration statement":


 цитата:
3 It is possible to transfer into a block, but not in a way that bypasses declarations with initialization. A program that jumps87 from a point where a variable with automatic storage duration is not in scope to a point where it is in scope is ill-formed unless the variable has scalar type, class type with a trivial default constructor and a trivial destructor, a cv-qualified version of one of these types, or an array of one of the preceding types and is declared without an initializer (8.5).



Однако компилятор MS VC++ 2010 игнорирует данное ограничение и позволяет передавать управление в область видимости переменной, имеющей тип класса, в котором определен нетривиальный деструктор, после ее объявления.

Следующий тестовый пример демонстрирует наличие этого бага в MS VC++ 2010
.
 #include "stdafx.h" 
#include <iostream>



int _tmain(int argc, _TCHAR* argv[])
{
struct A
{
~A(){ std::cout << "A::~A()\n"; }
int x;
};

goto M1;

{
A a;
M1:
a.x = 10;
}

return 0;
}


В этом примере с помощью оператора goto управление передается внутрь блока кода на метку M1, следующую за объявлением переменной a, которая имеет тип класса, в котором определен нетривиальный деструктор.

Никаких предупреждений или сообщений об ощибке компилятор не выдает.

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 21:34. Заголовок: Кстати сказать, в св..


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


#include	<iostream> 

int _tmain(int argc, _TCHAR* argv[])
{
int i = 2;

switch ( i )
{
case 0:
int j;
break;
case 1:
break;
default:
j = i;
std::cout << "j = " << j << std::endl;
break;
}
}


Здесь результатом вычисления выражения в switch будет значение 2, а потому управление сразу же перескочит на метку default:, минуя все вышестоящие метки. Тем не менее это не вызывет никаких проблем с использование переменной j которая объявлена в части предложения switch, которая относится к метке case 0:

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 28.07.12 22:02. Заголовок: Пришло подтверждение..


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


 цитата:
Posted by Microsoft on 23.07.2012 at 9:53

Hello,

We appreciate you reporting this bug, you're right it's bug in VC compiler with labels and global class names matching. We'll consider fixing this in a future release, in the meantime you know the workaround you can use in your code.

Thank you,
Ulzii Luvsanbat
Visual C++ Team



Решение по устранению этого бага будет рассматриваться в будущей (не уточняется какой) версии компилятора.

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

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 31.07.12 15:38. Заголовок: Пришел ответ и на мо..


Пришел ответ и на мое второе сообение о баге, когда управление передается в область объявления переменной, минуя ее объявление. На этот раз на мой взгляд ответ Майкрософт не логичен. С одной стороны, одни признали, что такой код является ill-formed, с другой стороны, они приводят пример, который на самом деле повторяет мой пример, но при этом ссылаются на конструктор по умолчанию, как на существенное различие с моим примером, хотя в моем случае имеется тривиальный конструктор по умолчанию, который создает сам компилятор.
Вот текст ответа от майкрософт:


 цитата:
Posted by Microsoft on 7/30/2012 at 5:23 PM

Hi,
Thanks for reporting the issue.
Yes, according to the standard, the program is ill-formed unless the variable has POD type and is declared without an initializer. But the compiler is not required to give warnings.
In your example, 'A' doesn't have constructor and 'goto' doesn't skip any initializations.
Compiler does give a warning or error (depends on whether there is destruction) if initiliaztion is skipped. For example:

struct S {
S();
};

int main()
{
goto L;
S s;
L:
return 0;
}



То есть, как видно из их примера, они добавили явное объявление конструктора по умолчанию и на этом основании считает, что что-то меняется. Это их утверждение In your example, 'A' doesn't have constructor совершенно не корректно, так как на самом деле имеется неявно созданный конструктор по умолчанию.

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

Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 07.10.14 23:22. Заголовок: Сыроежка, ты - много..


Сыроежка, ты - много о себе самовозомнил (правка адм.). (просто хотел чтобы ты знал, и другим будет полезно).
Это про срач - на goto, на придуманное вообще в С/С++&нетолько - людьми намного поумнее тебя,
и тем более ...на кучу людей его использующих(и не собирающихся прекращать это - только чтобы угодить, в ч.н.тебе...),
которых, к тому же, говном поливать ты смелый - только в сети, удалённо и фактически анонимно...

-------------
А, по теме: попробуй-ка, для примера, уменьши размер кода в switch с [очень]большим числом case, в конце которых 10-100-500 одинаковых строк кода (да хоть пара - но, каждый раз требующий дополнительное внимание и тем более мозг выносящих), причём не во всех case - так что невозможно вынести эти повторяющиеся строки за пределы switch.
Что не только:
1) весьма засоряет наглядность,
без goto-оптимизированный case запросто может занять не то что всю область окна кода, несколько экранов!
2) но и, если оптимизатор компилятора протупит(и не такое бывает!), не авто-сольёт - код разрастётся не мерянно,
притом - снизив производительность...; если ещё и case - больше кэша(-ей)(при исп.макросов так вообще - не проблема)
и тем более он в цикле с большим числом итераций - вообще, может снизить скорость [цикла] запросто почти до нуля...
3) тоже самое что и п.2. - но, просто при компилированни в режиме с выключенной оптимизацией,
напр. для повседневной отладки и так тормозной,или же для обхода багов, в сумме - глупо ещё сильней замедлять.
И да - условие(которое знаю тебе не понравится,но тем не менее!):
* не выносить дублирующися код - в ф-ии/методы, т.к.бывает просто это (просто)невозможно...
* не выносить дублирующися код - в ф-ии/методы, т.к.желательно его расположение поблизости, но никак не за несколько [десятков] экранов; а, если скажешь что `а... ф-ии надо делать - компактнее!`, то 1)ведь только таких вынесенных в отдельные ф-ии блоков - запросто могут быть десятки+...; 2) могут быть перед ними другие ф-ии - тоже вызываемые изнутри 3) в л.сл: не тебе - учить других! каждому надо писать как считаешь правильно и удобнее/нагладнее себе, а не как кто то там умничает и льёт своё говно на других;
* не выносить дублирующийся код - в ф-ии/методы, т.к. в некоторых случаях - не на последнем месте важна - скорость(особенно внутри циклов): т.е. минимум вызовов ф-й (впрочем, по тебе вижу что оптимизация для тебя - пустой звук)
(тем более с передачей параметров, вкл.нежелательность выноса локальных переменных в гл.пространство, тем более при рекурсиях/ты ещё про устарелость технологии рекурсия - мне тут раскажи.../ это не пройдёт, и в любом случае - засорять глобально пространство имён - функциями или глобальными `временными`-переменными... как по мне - ещё хуже стиль)
* или, тоже самое - но уже с другого бока: наглядность(вызов), см. ниже.
Даже с точки зрения размера тупо текста кода - что короче "goto NNN;" или "call NNNN();[\n]break;",
тем более чаще нужно передавать и локальные переменные + нредко - с возможностью изменения их:
"call NNNN(&lvar1,&lvar2,&lvar3,&lvar4,&lvar5,&lvar6,&lvar7,&lvar8,.....);[\n]break;" ?!...

А, как же - быстрый и притом визуально-компактыный выход из несколько-уровнёвого цикла!... Это кем надо быть чтобы такую операцию усложнять только с целью - сказать себе и другим: `Зато я не использую goto!`
И ведь эти примеры - далеко не единственные...
На вскидку ещё - тот же мой любимый переход в конец функции на её `ручную финализацию` при ошибках-и-нет [темболее когда не задействуются по каким либо причинам - исключения]? [Даже при использовании исключений] блоки завершения - могут запросто составлять большую часть ф-ии,увеличивая её как визуально так и по коду, если их не `удалять` - ...использованием goto. Но нет! Не модно, низзя! (И ведь не просто низзя - а, категорично низзя! как ты там говоришь - все кто не согласен с этим?...)


PS:
Кстати, недавно обратил внимание: в совремнных версиях некоторых Pascal'ей - goto поддерживается по полному Pascal-стандарту, т.е.может быть и вне тела функции/процедуры! (я уже даже представил себе выражение у некоторых...), а это уже - возможности оптимизации(и просто простор для всяких нетривиальных, и притом не обязательно усложняющих понимание - в т.ч.другими людьми, решений) уровня ассемблера! (но, тебе уверен этого не понять - так что пишу больше для других).

PS:
А, такие позорные проблемы у MS VS с goto-багом(и не только с ним) - явно как раз потому что там тоже такие же "фанатики" анти-goto(а, точнее даже - нечто иного,тематически куда масштабней, чему и названия в сумме сложно подобрать), потому то, ни программистами MS, ни даже QA - баг не был замечен. В т.сл.для них - даже просто его использование: само по себе - нонсенс! Но, думаю, тогда и не стоило таким доверять писать компилятор ...под Си!
И в результате: обычные пользователи этого компилятора(миллионы и суммарно - миллиарды, уже считая вместе с теми конечными-пользователями-созданного-ПО) - расплачиваются сверх-трудно-находимыми(программистами) и тем более - как обычно редко оперативно-исправляемыми ими пользователям, а чаще так и вовсе - никогда не-исправляемыми [опционально - фантомно-проявляющимися] багами...


Спасибо: 0 
Цитата Ответить



ссылка на сообщение  Отправлено: 08.10.14 10:41. Заголовок: Было бы хорошо, если..


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

Я уверен, что баги в компиляторе MS VC++ никак не связаны с тем, что там, в Microsoft имеются какие-то фанатики. По крайней мере это не связано с фанатизмом, а с осмысленным подходом к оператору goto. Если вы читали другие мои темы, то можете найти немало описаний багов компилятора GCC. Следует ли из этого, что там свои фанатики со своими пристрастиями?

Я думаю, что баги чаще всего связаны со сложностью самого языка C++, написания компилятора для него и обеспечения обратной поддержки и совместимости с различными расширениями компилятора и используемыми библиотеками.

Что касается оператора goto, то все языки программирования ведут свою родословную от машинных языков. Если, например, история происхождения человека на Земле до сих пор неизвестна, то история каждого из языков программирования хорошо изучена и описана во множестве письменных источников.

Каждый процессор имеет в своем наборе команд команды условных и безусловных переходов. Фактически, без этих машинных команд нельзя написать ни одной более-менее серьезной программы на машинном языке. Чтобы облегчить работу программистов, появились ассемблеры, которые ввели мнемонические имена для машинных команд, сохранив для пользователей доступ ко всем машинным командам. Затем появились языки более высокого уровня, которые, чтобы обеспечить совместимость с уже написанным кодом и облегчить его перенос на новый язык, ставили в соответствие машинным командам безусловного перехода оператор goto, как, например, это было сделано в языке FORTRAN.

Так что "умные люди" ничего не придумывали. Они использовали то, что было в их распоряжении. Но по мере того, как абстракции языков программирования все более отдалялись по эволюционной лестнице от своих прародителей, машинных языков, становилось все более очевидным, что использование оператора goto нарушает дисциплину написания программы и вносит в их код хаос. Именно поэтому, практически, ни в одной книге по языку C++ вы не найдете раздела, где бы описанию оператора goto отводилось много места. Его просто для справки упоминают, чтобы затем для читателя не было бы неожиданностью встретить оператор goto в каком-нибудь коде нерадивого программиста.

В настоящее время есть уже языки программирования высокого уровня, где оператор goto просто отсутствует. Например, в языке Effel.

Кстати сказать, язык C имеет репутацию языка ассемблера среди языков высокого уровня. Поэтому не удивительно, что в нем присутствует оператор goto, который по инерции наследуется всеми производными от C языками.

Я убежден, как я уже раньше писал, что чем ниже квалификация программиста, тем он рьянее защищает этот оператор.

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

Поэтому из их уст часто приходится слышать подобного рода примеры некоего кода, где, якобы, без goto не обойтись. Это напоминает легенду об Александре Македонском, который разрубил Гордиев узел. И оператор goto в примерах таких "продвинутых" программистов напоминают собой меч Александра Македонского, который просто и без затей решает проблему.

На самом деле все эти примеры демонстрируют не полезность оператора goto, а не умение писать структурированный код, в результате чего тот превращается в "Гордиев узел".

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

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

Операторы goto - это обычно замаскированные источники различных багов. Сколько мне приходилось иметь дело с кодом других программистов, использующих оператор goto, столько раз я находил баги в этих конструкциях.

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

Конечно легко поддастся соблазну и решить проблему вставкой оператора goto вместо того, чтоб реструктурировать код и сделать его более ясным. Но на то и дана квалификация программистов, чтобы уметь писать качественный код, а не ставить заплатки в виде оператора goto


Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 09.10.14 10:45. Заголовок: Хотя эта тема посвящ..


Хотя эта тема посвящена багам компилятора MS VC++ 2010, но тем не менее раз она затрагивает оператор ]goto и соответственно метки будет логичным указать в этой теме на существующие отличия между C и C++ относительно использования этих конструкций.

В C объявления не являются (исполняемыми) предложениями, в то время как в C++ объявления относятся к категории предложений. Поэтому в C нельзя ставить метку перед объявлением.

Что тогда делать, если в программе на языке C все-таки нужно разместить метку непосредственно перед объявлением? Для этого нужно будет использовать пустой оператор.

Следующие примеры программ демонстрируют это различие между C и C++.

C программа
 
#include <stdio.h>

int main( void )
{
int y = 0;

L1:;
int x = y + 10;

printf( "x = %d\n", x );

if ( y++ == 0 ) goto L1;

return 0;
}

C++ программа
 
#include <iostream>

int main()
{
int y = 0;
L1:
int x = y + 10;

std::cout << "x = " << x << std::endl;

if ( y++ == 0 ) goto L1;

return 0;
}


Вывод на консоль в обоих случаях будет одним и тем же
 
x = 10
x = 11


Как видно, в объявлении метки в C программе L1:; после двоеточия присутствует точка с запятой, которая задает пустой оператор.. Если эту точку с запятой убрать, то компилятор сообщит об ошибке.

Этот пример я привел не для того, чтобы кто-то обогатил свою практику использования оператора goto (нужно просто забыть, что в C и C++ существует этот оператор), а чтобы показать, насколько все же различны между собой C и C++.




Спасибо: 0 
ПрофильЦитата Ответить



ссылка на сообщение  Отправлено: 10.10.14 22:26. Заголовок: Кстати сказать, чтоб..


Кстати сказать, чтобы баги компиляторов языка C++ не связывались с неким фанатизмом и пристрастием их разработчиков, то замечу, что даже сегодня (на дату этого сообщения) обнаружил очередной баг компилятора GCC на www.ideone.com.

Так следующее объявление
 
bool b = std::cin;


успешно компилируется, несмотря на то, что класс std::basic_ios имеет функцию преобразования operator bool, объяаленную со спецификатором explicit




Спасибо: 0 
ПрофильЦитата Ответить
Ответ:
1 2 3 4 5 6 7 8 9
большой шрифт малый шрифт надстрочный подстрочный заголовок большой заголовок видео с youtube.com картинка из интернета картинка с компьютера ссылка файл с компьютера русская клавиатура транслитератор  цитата  кавычки моноширинный шрифт моноширинный шрифт горизонтальная линия отступ точка LI бегущая строка оффтопик свернутый текст

показывать это сообщение только модераторам
не делать ссылки активными
Имя, пароль:      зарегистрироваться    
Тему читают:
- участник сейчас на форуме
- участник вне форума
Все даты в формате GMT  3 час. Хитов сегодня: 3
Права: смайлы да, картинки да, шрифты да, голосования нет
аватары да, автозамена ссылок вкл, премодерация откл, правка нет