Когда мы используем printf, тогда мы используем спецификаторы формата (такие как% c,% p), но когда мы используем cout, мы не используем их, почему и что делается в фоновом режиме, потому что мы их не используем?
Я знаю, что они используются по-разному в c и c ++, но все же я хочу знать, как выполняется форматирование в cout, в то время как это делается в printf через спецификаторы формата.
В C ++ ostream::operator<<
перегружен для разных типов. Вы можете попытаться просмотреть вашу стандартную библиотечную реализацию, чтобы точно увидеть, как она выглядит, но она будет сводиться к чему-то, что примерно эквивалентно следующему:
class ostream
{
public:
ostream& operator<<( int val );
ostream& operator<<( float val );
ostream& operator<<( const char* val );
};
Реальная реализация будет намного сложнее, чем выше, но это примерно идея. Была надежда, что эта реализация будет более эффективной, чем printf, потому что компилятор может легче встроить код в случае необходимости. Учтите следующее:
int val = 0;
printf("%d\n", val);
std::cout << val << std::endl;
В случае printf наивно скомпилированная программа (скомпилированная компилятором без знания спецификаторов формата) должна будет выполнить синтаксический анализ «% d \ n» во время выполнения. Сравните это с вызовом std :: cout, и в этом случае компилятору просто нужно выяснить, какую перегрузку использовать, и затем он может встроить код.
Тем не менее, в стандарте c нет ничего, что говорило бы, что компилятор не может анализировать спецификаторы формата во время компиляции, если они доступны. На практике разница в производительности между библиотекой журналирования стиля c с использованием спецификаторов формата и c ++ ostreams составляет … нюансы.
Так как printf
правильно разработан и cout
имеет неприятное внутреннее состояние. С printf
способ, которым вы хотите отформатировать каждый аргумент, является явным в строке формата; нет скрытого состояния. С cout
Вы также можете управлять форматированием (такими как ширина поля и т. д.), но это скрытое состояние внутри объекта iostream. Если предыдущий пользователь потока оставил его в состоянии, отличном от заданного по умолчанию, вы поступите неправильно, если не сбросите его явно. Вы даже не хотите думать о том, что происходит в многопоточных случаях использования …
В основном ответом является перегрузка операторов. Функции могут иметь одно и то же имя, если они принимают разные параметры. operator<<
имя функции, о которой вы задаетесь вопросом Компилятор знает тип того, что вы пытаетесь распечатать, и вызывает правильный operator<<
,
Вот почему, если вы создаете свой собственный объект, вы не можете просто написать std::cout << yourObject;
и ожидайте, что это сработает так, как вы, вероятно, хотели бы. Вы должны указать, как это должно быть напечатано,
ostream& operator<<(ostream& os, const YourObject& rhs) {
os << rhs.member;
return os;
}
Но, к счастью, это уже было сделано для вас за кулисами в случае чего-то вроде int
, Увидеть: http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt2 для полного списка предоставленных перегрузок.