Если скомпилировать код ниже в Visual Studio x86 (Visual Studio Tools - командная строка разработчика для VS, команда "cl test.c" ) программа скопилируется, успешно выполнится и на консоль будет выведено: Result: Goodbye! (проверялось в 2010 и 2015 версии)
Но если этот код скомпилировать в gcc x86-64 под Linux, то исполняемая программа будет падать в Segmentation Fault.

Убедитесь в этом сами и попробуйте ответить, почему в Linux программа падает? Почему в Windows программа успешно работает? Для поиска ответа могут понадобиться средства отладки.

#include <string.h>
#include <stdio.h>

void copystring(char *s)
{
strcpy (s, "Goodbye!");
printf ("Result: %s\n", s);
};
int main()
{
copystring ("Hello, world!\n");
};

Комментарии
17.06.2015 в 09:43

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
Тут отладчик не нужен. И так всё очевидно.
17.06.2015 в 09:57

Flex Ferrum, что очевидно? тогда ответ в студию. ИМХО, совсем не очевидно.
17.06.2015 в 10:29

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
читать дальше
17.06.2015 в 10:51

Да, код некорректный. Но вопрос не в этом был.
Вопрос в том, почему этот код вызывает ошибку при компиляции gcc и не вызывает ошибку в mcvs! Почему разное поведение? В чем разница подходов компилирования, или, может быть, в способе исполнения бинарного кода?
17.06.2015 в 11:01

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
Trotil, потому что undefined behavior. UB - самое неприятное, что может быть в коде. И именно поэтому MSVC совершенно случайно даёт рабочую программу, а gcc - нет. И это ещё очень повезло, что программа падает. А то могла бы пуск ядерных ракет выполнить или диск форматнуть - поведение то не определено, а значит может быть каким угодно.
17.06.2015 в 11:12

Нет, это не совершенно случайно. Это связано с разным подходом к ... (а к чему, в этом и состоял мой вопрос).

Другими словами, это не случайно, потому что обладая определенными знаниями, можно совершенно точно предсказать, что в Linux этот код упадет, а в Windows - нет. И человек, который писал этот познавательный учебный пример, именно на такое поведение и рассчитывал.
17.06.2015 в 11:44

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
Другими словами, это не случайно, потому что обладая определенными знаниями, можно совершенно точно предсказать, что в Linux этот код упадет, а в Windows - нет. И человек, который писал этот познавательный учебный пример, именно на такое поведение и рассчитывал.
Да нет. Именно что случайно. :) Полагаться на некоторое конкретное поведение компилятора там, где в стандарте написано UB - это верный способ поотстреливать себе всё, что можно. Можно, конечно, заложиться на то, что MSVC (определённой версии) в случае компиляции C-программы будет располагать строковые литералы в R/W-сегменте памяти (а не в константном), но закладка эта так себе, скажем прямо. :)
17.06.2015 в 13:53

> в случае компиляции C-программы будет располагать строковые литералы в R/W-сегменте памяти (а не в константном)

Я согласен, что это вполне вероятная причина такого поведения и это очень похоже на правильный ответ :) , ну а вдруг нет и есть другая причина? Гипотезы надлежит проверять.
Кстати, если создать типовой win32 консольный проект в MSVC, и вставить функцию copystring и вызов её в tmain, то программа начинает падать.
17.06.2015 в 14:00

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
Trotil, ты лучше объясни: какой смысл искать ответ на вопрос, на который ответ искать не имеет смысла? :) У каждого конкретного компилятора (с конкретными настройками компиляции) может быть 100500 причин поступить так или иначе в случае обнаружения UB. Главное, что в коде UB. Падает код или нет - это следствие UB. :)
17.06.2015 в 14:14

Reflendey
Наверное, просто интересны особеннности кодогенерации конкретных компиляторов.

У меня вот другой вопрос возник, в связи с этим, возможно глупый, но раз уж тут собрались умные дядья... Зачем вообще UB компилируется, а не выдает ошибку? (в тех случаях, когда это возможно отследить, как в примере, понятно что сложные случаи статическим анализом не отлавливается)
17.06.2015 в 14:24

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
Зачем вообще UB компилируется, а не выдает ошибку?
Как говорят другие умные дядьки (которые занимаются этими вопросами в стандарте), если появляется возможность перевести UB из разряда UB в разряд ошибок компиляции - это делается. Но тут тоже надо понимать - совмещать компилятор ещё и со статическим анализатором кода? Гм...
17.06.2015 в 14:24

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
Зачем вообще UB компилируется, а не выдает ошибку?
Как говорят другие умные дядьки (которые занимаются этими вопросами в стандарте), если появляется возможность перевести UB из разряда UB в разряд ошибок компиляции - это делается. Но тут тоже надо понимать - совмещать компилятор ещё и со статическим анализатором кода? Гм...
17.06.2015 в 15:08

Puteror, некоторые вещи компиляторы умеют отслеживать. В gcc есть ключи -Wall, -Wextra, -pedantic для этого. Старый gcc4.4.7, к сожалению, этот случай не ловит. В новой не проверял.
По отдельности код функции легальный, что передача указателя на строку в некоторую функцию, что некоторые действия со строкой в функции, который помечен как char *.
Статические анализаторы выпускаются отдельно сторонними фирмами, и вроде успешно.

> ты лучше объясни: какой смысл искать ответ на вопрос
Не поверишь, но на свете есть люди, которым это может интересно и это достаточная причина, чтобы поискать ответ на этот вопрос.
Собственно, пример взят из этой книги: beginners.re/ . Её целевая аудитория - как раз те, которым интересно.
17.06.2015 в 16:32

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
некоторые вещи компиляторы умеют отслеживать. В gcc есть ключи -Wall, -Wextra, -pedantic для этого. Старый gcc4.4.7, к сожалению, этот случай не ловит. В новой не проверял.
4.7 тоже не ловит.

Не поверишь, но на свете есть люди, которым это может интересно и это достаточная причина, чтобы поискать ответ на этот вопрос.
Только вот зачем для этого отладчик то использовать? Генерируем из исходника ассемблерный текст и видим (под Linux):

Bingo!
17.06.2015 в 21:21

так а чо ему ловить-то.
На уровне компилятора отловится разве что преобразование строкового литерала в char* (и то, только крестовым компилятором, где эти литералы const char*).
Большего ему знать и не надо.
То, что строки кладутся в .rodata - это не более, чем поведение конкретного линковщика на конкретной платформе. А если, к примеру, платформа специфическая и там никому не нужна защита страниц от записи, то в сегмент данных будет всё замечательно записываться.
Если предположить, что кому-то не лень будет писать статический анализатор на это самое поведение линковщика на какой-то платформе, то и он отловит только самые тривиальные случаи (попытка записи по известному на этапе компиляции адресу, который находится в защищённой от записи секции). А в общем виде эта задача будет решаться только в рантайме.
17.06.2015 в 21:57

> поведение конкретного линковщика на конкретной платформе
Кодогенератора для конкретной платформы.
Энивей, всё что можно было показать (предупреждение на каст) уже было показано. А внутри функции уже корректный указатель, потенциально доступный для записи, а потому кидать предупреждения или ошибки мы не имеем права.
17.06.2015 в 22:12

IDDQD - Команда молодости нашей, команда, без которой мне не жить.
(и то, только крестовым компилятором, где эти литералы const char*).
В "крестовом" компиляторе это не const char*, а const char[]. Немного разные вещи. А в С (начиная с C99) строковый литерал определяется как массив char'ов с static-модификатором.