Почему вывод std :: cout полностью исчезает после отправки на него значения NULL - PullRequest
20 голосов
/ 11 августа 2011

Мне потребовалось некоторое время, чтобы понять, почему некоторые выходы cout, кажется, исчезают в эфире. Виновник:

std::cout<< "This line shows up just fine" << std::endl;
const char* some_string = a_function_that_returns_null();
if (some_string == 0)
    std::cout<< "Let's check the value of some_string: " << some_string << std::endl;

std::cout<< "This line and any cout output afterwards will not show up" << std::endl;

Выходные данные из приведенного выше фрагмента будут:

This line shows up just fine
Let's check the value of some_string:     

Таким образом, подача NULL в cout отключит все выходные впоследствии. Зачем? И как это исправить?

Это происходит не всегда - сотрудник с одинаковым кодом получает все ожидаемые результаты. И в случае, если вам интересно, почему я не могу просто запретить ввод NULL в cout с помощью оператора if: я работаю в большой кодовой базе и не знаю, где еще это происходит! Все, что я знаю, это заявления о том, что я никогда не появлялся.


Дополнительная информация:

a_function_that_returns_null() на самом деле getenv("HOST"). В командной строке через echo $HOST я проверил, что переменная HOST пуста. Если я сделаю export HOST= (Bash flavour), все результаты будут там. Я понятия не имею, что изначально содержит переменная HOST, и что getenv возвращает изначально, когда я изменяю переменную HOST; все, что я знаю, это (some_string == 0) правда.

Ответы [ 3 ]

27 голосов
/ 11 августа 2011
const char* some_string = a_function_that_returns_null();

Вы имеете в виду, что он буквально возвращает нулевой указатель?

[2003: 27.6.2.5.4]:

template<class traits>
basic_ostream<char,traits>& operator<<(basic_ostream<char,traits>& out, const char* s);

3. Требуется: s isненулевой.

Тогда потоковая some_string - это неопределенное поведение;Вы не можете разыменовать указатель, чтобы получить строку - даже пустую - если указатель недействителен.


Это не происходит постоянно - сотрудник с таким жекод получает все ожидаемые выходные данные

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

Однако изс точки зрения C ++, может произойти все что угодно ;в вашем конкретном случае ваша стандартная реализация библиотеки вполне может проверять нулевой указатель и устанавливать флаг ошибки в потоке вместо попытки разыменования указателя.Это его прерогатива.

(Вероятно, именно поэтому ваши последующие операции потока терпят неудачу: попытка записи в поток ничего не делает, когда установлен флаг ошибки.)

Например, libstdc ++поставляется с GCC 4.6.0, несмотря на то, что с именем s != 0 в качестве предварительного условия , делает делает это :

00325       if (!__s)
00326     __out.setstate(ios_base::badbit);
00327       else

Однако, вы должны не полагаться на это поведение ;он может изменить в любое время !


Так что просто не делайте этого.Если вам действительно нужно, передайте правильную, но пустую строку.

А что не так с std::string?

8 голосов
/ 11 августа 2011

Я вполне уверен, что cout << (char*)NULL имеет неопределенное поведение.Боюсь, что «Не делай этого» - лучший совет, который я могу предложить.

0 голосов
/ 11 августа 2011

Когда вы пытаетесь вывести const char*, поток печатает все байты, пока не достигнет '\0'. Это ведет к неопределенному поведению. Например, вы можете напечатать некоторые контрольные символы (например, '\n', '\r' и т. Д.) И получить непредсказуемый результат.

EDIT : На самом деле потоковой передачи указателя NULL достаточно для получения UB. Я не собираюсь удалять свой ответ из-за полезных комментариев.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...