Почему эта программа на С++ ведет себя по-разному на разных компиляторах?

Я читал это. Этот вопрос содержит следующую программу.

#include <iostream>
#include <cstdio>
#include <string>
int main()
{
    using namespace std;
    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString);
    cin.get();
    return 0;
}

Я пробовал это на g++ 4.8.1, но компиляция не удалась. g++ 4.8.1 дает следующий диагноз.

9 47 [Error] cannot pass objects of non-trivially-copyable type 'std::string {aka class std::basic_string<char>}' through '...' 
9 47 [Warning] format '%s' expects argument of type 'char*', but argument 2 has type 'std::string {aka std::basic_string<char>}' [-Wformat=]

Что означает эта ошибка? Должна ли эта программа компилироваться успешно или нет? Какой компилятор правильный (g++ или MSVS 2010)? Почему MSVS 2010 принимает этот код? Вызывает ли код неопределенное поведение при компиляции в MSVS 2010?

Удивительно: я попробовал это на ideone, который использует g++ 5.0, и на удивление он компилируется и работает нормально. (См. живую демонстрацию здесь). g++ 5.2.0 выдает предупреждение, когда я компилирую этот код. (См. живую демонстрацию здесь). Почему он отлично компилируется на ideone, но не работает на g++ 4.8.1? g++ 4.8.2 (выдает тот же диагноз, что и g++ 4.8.1, 4.9.0,4.9.1,4.9.2 (выдает ошибку, а не предупреждение). g++ 5.1.0 выдает предупреждение, но программа по-прежнему компилируется и работает нормально.

Почему разные версии g++ ведут себя по-разному при компиляции вышеуказанной программы? Это ошибка в g++? Clang также отклоняет этот код для компиляции в ответ на ответ, данный @TemplateRex


person Destructor    schedule 17.09.2015    source источник
comment
Он действительно нормально работает? Ни одна из двух живых демонстраций не показывает содержимое myString правильно.   -  person MikeCAT    schedule 17.09.2015
comment
Это выдает ошибки, потому что вы делаете что-то недопустимое, а именно используете объект C++ со старой функцией C, что просто невозможно.   -  person Some programmer dude    schedule 17.09.2015
comment
@JoachimPileborg: тогда почему он успешно компилируется без ошибок на g++ 5.1.0, 5.2.0?   -  person Destructor    schedule 17.09.2015
comment
@StillLearning: это не дубликат. Если это дубликат, я бы не стал связывать этот вопрос при публикации этого вопроса.   -  person Destructor    schedule 17.09.2015
comment
Это буквально тот же пример, и комментарий здесь все еще актуален: плохая книга.   -  person MSalters    schedule 17.09.2015
comment
@PravasiMeet - ну мне кажется то же самое и уже есть очень хороший ответ   -  person 4386427    schedule 17.09.2015
comment
См. также stackoverflow.com/questions/10083844/, в котором конкретно рассматривается, почему разные версии могут вести себя по-разному.   -  person MSalters    schedule 17.09.2015
comment
@MSalters: Спасибо за ссылку.   -  person Destructor    schedule 17.09.2015


Ответы (1)


Ошибки Clang с «ошибкой: невозможно передать нетривиальный объект типа« строка »(также известная как «basic_string») в функцию с переменным числом аргументов; ожидаемый тип из строки формата был« char * »[-Wnon-pod-varargs]» и предлагает исправить "примечание: вы хотели вызвать метод c_str()?"

#include <iostream>
#include <cstdio>
#include <string>
int main()
{
    using namespace std;
    string myString = "Press ENTER to quit program!";
    cout << "Come up and C++ me some time." << endl;
    printf("Follow this command: %s", myString.c_str());
    cin.get();
}

и это похоже, работает.

person TemplateRex    schedule 17.09.2015
comment
Если вы удалите вызов функции c_str(), то она завершится ошибкой при компиляции и выдаст те же ошибки, что и g++ 4.8.1, 4.8.2, 4.9.0, 4.9.1 и 4.9.2. - person Destructor; 17.09.2015
comment
@PravasiMeet printf не подходит для std::string, просто вставьте в него c_str() и вы в деле - person TemplateRex; 17.09.2015
comment
Да, верно. но вопрос в том, почему разные компиляторы по-разному реагируют при компиляции этой программы? - person Destructor; 17.09.2015
comment
@PravasiMeet в Вопросах и ответах, приведенных в комментариях к вашему OP, указано, что передача std::string в printf является неопределенным поведением. В этом случае может случиться что угодно, включая успешную компиляцию и вывод. Но не стоит полагаться на это. - person TemplateRex; 17.09.2015
comment
@PravasiMeet — ваша обязанность сопоставить строку формата с параметрами. Некоторые компиляторы могут быть милы и сообщать вам, когда вы ошибаетесь, но это не обязательно. С некоторыми соглашениями о вызовах и в реализациях, где std::string имеет указатель в качестве своего первого члена, printf может полагать, что получает строку в стиле C и корректно отображает ее случайно. - person Bo Persson; 17.09.2015