А вы знаете особенности используемого вами компилятора C++? Наверняка. А компилятора стороннего производителя? А gcc? :) Интересно, почему я это спрашиваю? Потому что недавно мы с командой участвовали в очередном соревновании по спортивному программированию, и на тестирующем сервере были только свободные компиляторы: gcc, freepascal и т.п., а вот на машинах участников стояла винда… И, естественно, компиляторы тоже были «виндовые». В общем, в качестве среды разработки стояла Visual C++ Express. Казалось бы, ну и что?! Но это вылилось в постоянную борьбу с компилятором за то, чтобы наше решение наконец-таки скомпилировалось на сервере. У нас, естественно, все работало. Так я узнал некоторые особенности gcc по сравнению с Visual C++, чему и посвящен этот пост.
Наверное, все знают, что функция main() по стандарту C++ должна возвращать int. Хотя Visual C++ позволяет писать void main().
Наверное, уже не все, но все еще многие, знают, что в стандарте C++ нет типа _int64. Это «придумка» Microsoft. По стандарту нужно писать long long.
А теперь, кто знает, в какой библиотеке находится функция getchar()? Подумайте. В Visual C++ для её вызова нужно подключить conio.h. А в gcc? Затаили дыхание… Функция getchar() в компиляторе gcc находится в библиотеке stdio.h! Мало того, в gcc на сервере вообще не было библиотеки conio.h!
Ну ладно, это еще не так сложно обнаружить. Но мы наткнулись на еще несколько «странностей», благодаря которым получили несколько compilation error.
Первая. Это то, что gcc не хочет компилировать строчку типа
1 |
int; |
Да, я понимаю, что необходимость такой строчки в программе сомнительна. Но иногда бывает, что начнешь объявлять переменную какого-нибудь длинного типа, а потом передумаешь это делать, но объявление решишь оставить – вдруг пригодится… А имя переменной задать то не успел еще! Вот так у меня и было. Самое дурацкое тут, что заметить такую «бессмысленную» строку в коде сложно – на нее просто не обращаешь внимания. Однако, Visual C++ такое написание спокойно проглатывает и не ругается.
Следующее, что повергло нас в шок:
1 |
if (n+1>p || m-1<r){} |
Вы думаете, что этот код у вас скомпилируется на том компиляторе? Если да, то вы ошибаетесь. А вот такой?
1 |
if ((n+1>p) || (m-1<r)){} |
Да, вы правильно чувствуете подвох в вопросе: этот код тоже даст ошибку при компиляции. Решение вроде простое, по-паскалевски логичное, но оно дико бесит:
1 |
if (((n+1)>p) || ((m-1)<r)){} |
Да «старые» скобки тут лишние скорее всего, но то, что gcc не может обработать это выражение, у меня вызвало неприятный привкус паскаля.
Из-за этих compilation error у нас было худшее штрафное время среди команд, решивших столько же задач.
PS: На сервере стоял компилятор GNU C++ 4.5.2
Полезная статья? Их будет больше, если вы поддержите меня!