2) Тут недавно код предложили один, помогите разобраться
#include <iostream>
#include <fstream>
int main()
{
using namespace std;
// перенаправим clog в файл my.log
ofstream log("my.log");
streambuf* original_clog_buffer(clog.rdbuf(log.rdbuf()));
clog << "My application has started successfully.\r\n";
// ...
clog << "My application shuting down...\r\n";
// вернем clog оригинальный буфер
clog.rdbuf(original_clog_buffer);
return 0;
}
Ну в общем всё ясно, кроме:
Чем clog отличается от cerr (ну типа что clog использует буфер, но это както не очень много мне даёт, что за буфер, где буфер)
В общем запутался в этих строчках:
rdbuf что это функция? Которая меняет буферы? и возвращает указатель на текущий?
То есть в первой строке мы устанавливаем буфер для clog буфер от log, точнее перенаправляем.
Но вот я ни как не могу понять что значит original_clog_buffer();
В MSDN накопал похожий код, только вот такой
Как я понипаю разницы нет ни какой, то есть в нашем случае () равно =, то есть присваение.
Это так?
Как самому сделать подобное? (класс где вместо = можно использовать () )
Ну и на конец в чём разница clog, cerr, cout?
Здравствуйте, Calc, Вы писали:
C>1) Для чего это надо и какую пользу это даёт C>
C>#pragma pack (push, 1)
C>#pragma pack (pop)
C>
Определяет выравнивание элементов структур
Например
#pragma pack (push, 1) // сохранить текущее; установить выравнивание 1 байтstruct aaa {
char m1, m2;
}; // sizeof(aaa) == 2#pragma pack (pop) // восстановить сохраненное#pragma pack (push, 4) // сейчас обычно такое умолчаниеstruct bbb {
char m1, m2;
}; // sizeof(bbb) == 8#pragma pack (pop)
C>2) Тут недавно код предложили один, помогите разобраться C>Чем clog отличается от cerr (ну типа что clog использует буфер, но это както не очень много мне даёт, что за буфер, где буфер)
Буферизация в обычно сильно ускоряет ввод/вывод (типа кеша)
Не перемешивать вызовы clog и cerr — будут чудеса
C>Как я понипаю разницы нет ни какой, то есть в нашем случае () равно =, то есть присваение. C>Это так?
Ага — в C++ инициализировать обычно можно как копированием, так и конструированием
в т.ч. и для простейших типов.
Здесь () — конструктор.
C>Ну и на конец в чём разница clog, cerr, cout?
clog==cerr с точностью до буферизации.
Т.е. clog заточен под большой объем вывода "ошибок" на консоль.
A cout — это для вывода "обычной" информации на консоль.
Разделение позволяет перенаправить информацию одной "значимости",
что здесь и было сделано — с консоли в файл.
Это все для упаковки членов класса и экземпляров класса в памяти. Каждый класс занимает объем памяти кратный константе упаковки.
Представь что у тебя в одном классе 6 переменных типа char.
*Пример из MSDN*
struct s
{
int i; //выровнен на байт 0, размер 4short j; //выровнен на байт 4, размер 2double k; //выровнен на байт 8, размер 8
};
Это при упаковке по 4 байта. Между j и k есть целых(!) два байта пустого и неиспользованного пространства
При упаковке по одному байту они будут плотно прилегать друг к другу. Это несколько неприятно будет для k — ее будет тяжело прочитать так как она 8 байтная, но не выровнена на 8 байтовую границу.
А синтаксис с прагмами — это для удобства. Первая прагма push сохраняет текущие настройки в стеке и выставляет этот параметр в 1. Вторая прагма восстанавливает настройки из стека.
> > 2) Тут недавно код предложили один, помогите разобраться > >
> #include <iostream>
> #include <fstream>
>
> int main()
> {
> using namespace std;
>
> // перенаправим clog в файл my.log
> ofstream log("my.log");
> streambuf* original_clog_buffer(clog.rdbuf(log.rdbuf()));
>
> clog << "My application has started successfully.\r\n";
>
> // ...
>
> clog << "My application shuting down...\r\n";
>
> // вернем clog оригинальный буфер
> clog.rdbuf(original_clog_buffer);
>
> return 0;
> }
>
>
clog cerr cout — это три разных предопределенных потока для разных назначений. При желании можно будет завести три консольных окна для вывода и выводить их по отдельности... В одном окне будут сообщения об ошибках, в другом логи исполнения программы, а в третьем пользовательский вывод. (а cin сделать клавиатурным вводом с удаленной машины 8)
Теперь по коду. Эта rdbuf принимает новый буффер и отдает пользователю на растерзание старый.
А вот то что было со скобочками и равенствами — это далеко не присваивания. Это конструкторы копирования. (хоть это и чуть чуть похоже на присваивание)
Буффер нельзя создать просто так... надо сразу (при конструкции) дать куда выводить все то что у него накопится, вот по этому тут такая сложная конструкция.
Если отобрать просто так буффер у потока, то потом его никто не уничтожит! Поэтому его нужно отобрать, сохранить и вернуть назад когда он больше не нужен. В случае вин32 это не так и страшно (ну, повиснет там программа когда закрываться будет и делов-то), а вот в случае дос — это могло привести к плохим последствиям.
Здесь проведено примерно следующее: стандартный буффер clog был подменен буффером от log, а старый стандартный буффер clog был сохранен в original_clog_buffer прозапас. В конце его отдали назад. За буффер log можно не беспокоиться, его пришибет log самостоятельно...
Кто скажет что это девочка, пусть первым бросит в меня камень! (с)О.Бендер
Здравствуйте, size_t, Вы писали:
_>clog cerr cout — это три разных предопределенных потока для разных назначений.
Ну это я знаю, а с физической стороны скажем можно вместо cout использовать cerr или clog (ну конечно так делать ни кто не будет, но всё же)
Вроде они классы. Вроде у них общий родитель.
И вообще где можно подробно прочесть о членах этих так называемых классов?
Здравствуйте, Calc, Вы писали:
C>2) Тут недавно код предложили один, помогите разобраться
C>
C>#include <iostream>
C>#include <fstream>
C>int main()
C>{
C> using namespace std;
C> // перенаправим clog в файл my.log
C> ofstream log("my.log");
C> streambuf* original_clog_buffer(clog.rdbuf(log.rdbuf()));
C> clog << "My application has started successfully.\r\n";
C> // ...
C> clog << "My application shuting down...\r\n";
C> // вернем clog оригинальный буфер
C> clog.rdbuf(original_clog_buffer);
C> return 0;
C>}
C>
C>Ну в общем всё ясно, кроме: C>Чем clog отличается от cerr (ну типа что clog использует буфер, но это както не очень много мне даёт, что за буфер, где буфер)
По-умолчанию, буферы потоков clog, cerr, cout пишут в стандартный поток stdout. Этот поток по-умолчанию направлен в консоль.
В стандартной библиотеке форматированный и неформатированный ввод/вывод осуществляется разными классами. Классы-наследники std::basic_streambuf<> содержат функции только для неформатированного ввода/вывода. Классы std::basic_ostream<>, std::basic_istream<>, std::basic_iostream<> агрегируют экземпляр std::basic_streambuf<>, занимаются форматированием и пишут/читают свои буферы. Буфер отвечает за то, куда/откуда будут поступать данные. Заменив у потока буфер другим буфером мы направляем ввод/вывод потока в этот другой буфер.
C>В общем запутался в этих строчках: C>
C>streambuf* original_clog_buffer(clog.rdbuf(log.rdbuf()));
// тоже самое, что и
streambuf* original_clog_buffer = clog.rdbuf(log.rdbuf());
C>...
C>clog.rdbuf(original_clog_buffer);
C>
C>rdbuf что это функция? Которая меняет буферы? и возвращает указатель на текущий?
Это перегруженная функция:
_Mysb* rdbuf() const; // возвращает указатель на буфер потока
_Mysb* rdbuf(_Mysb* _Strbuf) // заменяет буфер потока на новый и возвращает указатель на старый
C>То есть в первой строке мы устанавливаем буфер для clog буфер от log, точнее перенаправляем.
Точно.
C>Но вот я ни как не могу понять что значит original_clog_buffer(); C>В MSDN накопал похожий код, только вот такой C>
> А как выравнивание влияет на выполнение программы?
Чем правильнее, тем быстрее 8)
Это особенность процессора. Если он запрашивает n-байтное слово не выравненное на его n-байтную границу, то (при чтении из кэша) будет загружаться 2*n+1 тактов, по одному байту. Еще одна плохая вещь может произойти если переменная будет пересекать границу кэш линии... там еще куча тактов пройдет чтобы ее туда подгрузить. И это все так на наших X86 процессорах. На каком нить RISC посложнее это вообще приведет
Знаешь чем отличаются нормальные программы от кривых? Тем что в нормальных все выровнено, а не криво.
Здравствуйте, size_t, Вы писали:
>> А как выравнивание влияет на выполнение программы? _>Чем правильнее, тем быстрее 8) _>Это особенность процессора. Если он запрашивает n-байтное слово не выравненное на его n-байтную границу, то (при чтении из кэша) будет загружаться 2*n+1 тактов, по одному байту. Еще одна плохая вещь может произойти если переменная будет пересекать границу кэш линии... там еще куча тактов пройдет чтобы ее туда подгрузить. И это все так на наших X86 процессорах. На каком нить RISC посложнее это вообще приведет _>Знаешь чем отличаются нормальные программы от кривых? Тем что в нормальных все выровнено, а не криво.
А что считать кривы? Когда выравнивание 4 или 1?
Или всё расчитывать надо?
YVR>>#pragma pack (push, 4) // сейчас обычно такое умолчание
YVR>>struct bbb {
YVR>> char m1, m2;
YVR>>}; // sizeof(bbb) == 8
YVR>>#pragma pack (pop)
YVR>>
EX>Вообще-то в последнем случае тоже будет 2.
Согласен. Грубо ошибся
EX>А вообще обычно отключение выравнивания нужно если EX>ты собираешься, например, вычитывать эту структуру из EX>файла или сетки.
EX>Или передавать массив структур во "чужую" библиотеку. EX>В этом случае обычно бывает какая-то договорённость EX>на выравнивание.
... или в память по-больше напихать (пусть и за счет некоторой потери производительности).
>_>Знаешь чем отличаются нормальные программы от кривых? Тем что в нормальных все выровнено, а не криво.
>Возьмём мой класс:
>Вот интересно узнать, что к чему пресовать. >А где можно почитать о выравнивании? >Ссылка, книга или ещё что нибудь.
Там у тебя нечего прессовать. Все переменные по 4 байта (если для win32, а не win64).
Ставишь упаковку по 4 байта (она вроде как по дефолту стоит). Если бы были какие нить переменные типа char, short int и так далее, тогда можно было бы посжимать чего нить.
Вообще — хорошее правило для быстродействия — чтобы выравнивание не страдало надо упаковывать класс по максимальной длине элементарных переменных (элементарные, это то чем оперирует процессор, байты, инты, чары, флоуты, даблы, указатели и иже с ними).
На практике такое требуется только когда работаешь с предопределенными стандартами (например в структуре должны быть подряд упакованы char (1b), short int (2b), float(4b), char(1b) то без указаний для выравнивания — не жить); когда в классе только хранятся данные (редкий случай), а не используются для чтения; ну и все...
Вообще, при программировании под 32(64) разрядную среду упаковку надо ставить не менее 4(8) а то это тоже может привести к потерям скорости или неработоспособности (для супер навороченных risc систем).
Здравствуйте, size_t, Вы писали:
_>например в структуре должны быть подряд упакованы char (1b), short int (2b), float(4b), char(1b) то без указаний для выравнивания — не жить
А тут какое выравнивание делать?
1 или по величине самого большого члена?
> _>например в структуре должны быть подряд упакованы char (1b), short int (2b), float(4b), char(1b) то без указаний для выравнивания — не жить > > А тут какое выравнивание делать? > 1 или по величине самого большого члена?
В данном случае надо 1, но это приведет к потерям скорости если начать записывать в тот самый int или float. Чтобы этих потерь небыло надо поставить 4, но (!) тогда распределение их в памяти изменится, что приведет к несовместимости с некой спецификацией, которая требовала именно такого расположения данных
Здравствуйте, size_t, Вы писали:
>> _>например в структуре должны быть подряд упакованы char (1b), short int (2b), float(4b), char(1b) то без указаний для выравнивания — не жить >> >> А тут какое выравнивание делать? >> 1 или по величине самого большого члена?
_>В данном случае надо 1, но это приведет к потерям скорости если начать записывать в тот самый int или float. Чтобы этих потерь небыло надо поставить 4, но (!) тогда распределение их в памяти изменится, что приведет к несовместимости с некой спецификацией, которая требовала именно такого расположения данных