<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Блог о программировании &#187; C/C++/C#</title>
	<atom:link href="http://about-programming.ru/category/ccc.html/feed" rel="self" type="application/rss+xml" />
	<link>http://about-programming.ru</link>
	<description>Блог о программировании, Assembler, C, C++, C#, Delphi, Pascal, Java, PHP, Windows XP</description>
	<lastBuildDate>Sat, 17 Dec 2011 19:07:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Что такое QT?</title>
		<link>http://about-programming.ru/chto-takoe-qt.html</link>
		<comments>http://about-programming.ru/chto-takoe-qt.html#comments</comments>
		<pubDate>Tue, 14 Dec 2010 13:52:47 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=676</guid>
		<description><![CDATA[1. Что такое QT? ================= QT &#8212; это кроссплатформенная библиотека, целью которой является вытеснение нативных API из ваших программ. Сейчас Qt &#8212; это огромный объектно-ориентированный комбайн, в большинстве случаев позволяющий обойтись без привлечения каких-либо иных библиотек. В первую очередь Qt &#8212; отличное средство для создания графического пользовательского интерфейса (GUI). В состав Qt входит дизайнер, позволяющий [...]]]></description>
			<content:encoded><![CDATA[<p>1. Что такое <em>QT</em>?<br />
=================<br />
<strong>QT</strong> &#8212; это кроссплатформенная библиотека, целью которой является вытеснение нативных API из ваших<br />
программ. Сейчас Qt &#8212; это огромный объектно-ориентированный комбайн, в большинстве случаев<br />
позволяющий обойтись без привлечения каких-либо иных библиотек.<br />
В первую очередь Qt &#8212; отличное средство для создания графического пользовательского<br />
интерфейса (GUI). В состав Qt входит дизайнер, позволяющий легко создавать графические интерфейсы<br />
для вашего приложения.<br />
Вам не придется заботиться о написании файлов сборки для каждой из платформ, за вас это сделают Qt.<br />
Достаточно просто написать файл проекта, в который внести все используемые файлы, и файл<br />
сборки можно будет создать одним вызовом утилиты qmake (естественно, под управлением целевой<br />
платформы). От себя добавлю, что иногда этот файл приходится править руками (а как же).<br />
О значимости данной библиотеки говорит хотя бы то, что она используется в таких успешных проектах,<br />
как Borland C++ Builder 6 и Opera.<span id="more-676"></span></p>
<p>2. Где достать Qt?<br />
================<br />
Библиотека поставляется по нескольким лицензиям, одни из которых &#8212; платные, другие &#8212; нет. Под<br />
оконную систему X11 всегда можно с сайта www.trolltech.com легально<br />
взять GPL-версию <strong>Qt</strong> (и использовать, естественно, только<br />
в некоммерческих проектах). С системой Windows дело обстоит сложнее, поскольку, по мнению верхушки<br />
TrollTech, эта система не является ареной OpenSource-разработки. Последняя бесплатная версия для<br />
Windows &#8212; 2.3.0. Но для находчивых людей это не проблема, есть сеть eDonkey <img src='http://about-programming.ru/wp-includes/images/smilies/icon_wink.gif' alt=';-)' class='wp-smiley' />  Текущей на данный<br />
момент является версия 3.3.1. В скором времени ожидается версия 4.</p>
<p>3. Технические подробности Qt<br />
=============================<br />
Означало Qt &#171;работало&#187; на пользовательский интерфейс. Вот именно поэтому эта часть библиотеки наиболее<br />
используема и наиболее развита. интересен подход к позиционированию виджетов (виджет &#8212; элемент<br />
GUI, всё что рисуется на окошке, включая его само) &#8212; система слоёв (layout) позволяет вам забыть об абсолютном позиционировании, как о странном сне. Теперь класс Layout сам следит за тем, что вы делаете с, например, главным окном и позиционирует все внутренние виджеты вслед за изменением геометрии этого окошка.<br />
Центральной идеей Qt является сигнально-слотовый механизм, реализующий взаимосвязь между объектами.<br />
Этот механизм реализован посредством прекомпиляции, что позволяет использовать его без всяких<br />
ухищрений (если вы заинтересованы в Qt, прямо в данный момент забудьте о callback-вызовах ).<br />
Каждый Qt-объект (не только вызуальные элементы!) может генерировать некоторые сигналы, жестко<br />
за�?итые в структуру его класса. Сигнал &#8212; это функция, объявленная в специальной секции signals<br />
и не имеющая реализации (&#171;тела&#187;) а только передаваемые аргументы. К сигналу объекта (заметьте, не класса) могут быть подключены слоты. Слот &#8212; это всего ли�?ь метод, также объявленный в специальных секциях &#171;slots&#187;. Слоты<br />
могут быть доступными (секция &#171;public slots&#187;), защищенными (&#171;protected slots&#187;) и<br />
скрытыми (&#171;private slots&#187;). При помощи специального метода connect слот подсоединяется к сигналу.<br />
Неболь�?ой пример:</p>
<p><code> connect(myValueDetector, SIGNAL(ValueChange( Value a),<br />
myApplicationUpdater, SLOT(onValueChange( Value a ))));</code></p>
<p>После чего при каждом &#171;испускании&#187; сигнала ValueChange объектом myValueDetector<br />
будет вызываться слот onValueChange объекта myApplicationUpdater.<br />
Плюсы &#8212; к одному сигналу можно подключить несколько слотов.<br />
Минусы &#8212; один слот нельзя использовать для нескольких сигналов (например, для обработки группы кнопок). Сравните с системой событий VCL/CLX &#8212; там как раз всё наоборот. Рассмотрим неболь�?ой пример использования сигнально-слотового механизма:</p>
<p><code>//то, что инициирует сигнал для изменения<br />
class aValueDetector:public QObject<br />
{<br />
Q_OBJECT // нужно для объявления сигналов и слотов<br />
public:<br />
aValueDetector( Value a );<br />
signals:<br />
ValueChange( Value a );<br />
}<br />
//то, что его сможет обработать<br />
class aApplicationUpdater:public QObject<br />
{<br />
Q_OBJECT<br />
public:<br />
aApplicationUpdater();<br />
public slots:<br />
onValueChange( Value a );<br />
}<br />
// то, что всем управляет<br />
class aApplication<br />
{<br />
public:<br />
aApplication()<br />
{<br />
//некоторый код<br />
..................<br />
//а вот теперь самое главное<br />
connect(myValueDetector, SIGNAL(ValueChange( Value a )),<br />
myApplicationUpdater, SLOT(onValueChange( Value a ))));<br />
// причем, заметьте, один сигнал может вызывать и другой сигнал и иметь несколько коннектов<br />
// одновременно<br />
}<br />
protected:<br />
aValueDetector* myValueDetector;<br />
aApplicationUpdater* myApplicationUpdater;<br />
}</code></p>
<p>Как видите, код &#171;немного&#187; отличается от стандартного C++. Данный текст подаётся на вход мета-компилятора moc, который из него уже производит стандартный код C++, который затем компилируется любым компилятором. Moc отличает &#171;свои&#187;, т.е. поддерживающие сигнально-слотовый механизм, классы от стандартных по ключевому слову Q_OBJECT в самом начале объявления класса.</p>
<p>Перечислим основные достоинства ядра библиотеки Qt:<br />
* встроенная поддержка Unicode и локализации (очень хоро�?о и очень правильно реализованной, смею<br />
заметить). В Qt4 обещают новый механизм рендеринга �?рифтов, поддерживающий Unicode.<br />
* мощные события и фильтры событий (событие &#8212; это что-то вроде универсального сигнала, который можно посылать любому виджету, распознавать и соотвествующим образом обрабатывать с помощью фильтров. Например нажатие различных клави�?)<br />
* многофункциональные управляемые интервалами таймеры которые делают возможным просто и быстро<br />
вставлять много разных заданий в управляемый событиями ГП�?.<br />
* иерархические и настраиваемые объектные деревья, организующие принадлежность объектов естественным<br />
образом.<br />
* защищенные указатели QGuardedPtr, которые автоматически принимают значение NULL при<br />
уничтожении соответствующего объекта, в отличие от обычных указателей в C++, которые в этом<br />
случае становятся &#171;неопределенными указателями&#187;.<br />
* Удобная документация, доступная и на русском языке (ссылки к сожалению не знаю, но могу с удовольствием выслать по заявке).</p>
<p>В состав ядра библиотеки входят как классы для построения GUI (например: метка, поле ввода, кнопка и<br />
т.п.), так и классы, предназначенные для организации различных струтур хранения данных (например,<br />
списковых), работы с файлами, сетевого взаимодействия и многого другого. Некоторые из этих<br />
возможностей реализованы в виде дополнительных модулей:<br />
* модуль Canvas, мощный инструмент для работы с двухмерной графикой. Он использует принцип<br />
структурирования графики, что, несомненно, будет полезно в программировании простых двухмерных<br />
игр и подобного рода вещах. Холст состоит из нескольких &#171;элементов&#187;, каждый элемент представлен<br />
объектом. Поддерживается также ряд интересных возможностей, таких как collision-detection, перемещение(нет во фри�?ных версиях под виндой <img src='http://about-programming.ru/wp-includes/images/smilies/icon_sad.gif' alt=':-(' class='wp-smiley' /> (( )<br />
объектов с определенными скоростями по осям. Подробнее читаем по ссылке:<br />
Ссылка<br />
* модуль Network, обеспечивающий поддержку сети в приложениях.<br />
* модуль OpenGL, позволяющий работать с трехмерной графикой при помощи портабельной библиотеки<br />
OpenGL. Поддерживается с версии 2.3.2.<br />
* модуль SQL, реализующий доступ к базам данных из приложений Qt. Данный модуль разбит на три уровня:<br />
пользовательский (элементы интерфейса), программный (абстрактный доступ к базам данных) и уровень<br />
драйверов.<br />
* модуль Table, предоставляющий в ва�?е распоряжение сетку для отображения табличных данных. Сетка<br />
являет собой очень мощный и гибкий интерфейс, работать с которым &#8212; одно удобольствие<br />
* модуль XML, использующий интерфейс SAX2 и реализацию DOM второго уровня.</p>
<p>Это далеко не полный перечень возможностей Qt.</p>
<p>3. Как написать простенькое приложение на <strong>QT</strong>?<br />
=================================================<br />
Напишем файлик main.cpp следующего содержания:</p>
<p><code>#include<br />
#include<br />
int main( int argc, char **argv )<br />
{<br />
QApplication a( argc, argv ); // ну понятно, что без аппликухи никуда <img src='http://about-programming.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
QPushButton hello( "Привет, Мир!", 0 ); // Создаём простенькую кнопочку<br />
hello.resize( 100, 30 ); // растягиваем её, можно при желании и на весь экран <img src='http://about-programming.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
a.setMainWidget( &amp;hello ); // Делаем кнопку основным виджетом, это нужно для того, чтобы при закратии этой самой кнопки всё приложение завершило свою работу<br />
hello.show(); // это чтобы нашу красоту все увидели <img src='http://about-programming.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
return a.exec(); // и как говориться "Поехали" copyright by Y. Gagarin <img src='http://about-programming.ru/wp-includes/images/smilies/icon_smile.gif' alt=':-)' class='wp-smiley' /><br />
}</code></p>
<p>Теперь напишем файл проекта под это дело (simple.pro):</p>
<p><code>PROJECT = simple<br />
TEMPLATE = app<br />
CONFIG = qt warn_on debug<br />
SOURCES = main.cpp<br />
TARGET = simple</code></p>
<p>В командной строке наберем:</p>
<p><code>qmake simple.pro</code></p>
<p>А теперь черед утилиты make: приложение готово Запускаем, наблюдаем окошко с кнопочкой.</p>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/chto-takoe-qt.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Что такое traits?</title>
		<link>http://about-programming.ru/chto-takoe-traits.html</link>
		<comments>http://about-programming.ru/chto-takoe-traits.html#comments</comments>
		<pubDate>Tue, 14 Dec 2010 13:49:14 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=674</guid>
		<description><![CDATA[Что такое traits? Вступление В данной статье я попытаюсь рассказать, что такое traits. Будут рассмотрены некоторые примеры применения traits, которые будут заключаться как в использовании traits в на?ем коде, так и в возможных способах рас?ирения стандартной библиотеки C++, которая тоже использует traits. Также будут рассмотрены возможные проблемы, которые могут возникнуть при рас?ирении стандартной библиотеки C++. [...]]]></description>
			<content:encoded><![CDATA[<p>Что такое <strong>traits</strong>?</p>
<p><strong>Вступление</strong><br />
В данной статье я попытаюсь рассказать, что такое <strong>traits</strong>. Будут рассмотрены некоторые примеры применения <b>traits</b>, которые будут заключаться как в использовании traits в на?ем коде, так и в возможных способах рас?ирения стандартной библиотеки C++, которая тоже использует <em>traits</em>. Также будут рассмотрены возможные проблемы, которые могут возникнуть при рас?ирении стандартной библиотеки C++.</p>
<p><strong>Для кого написана данная статья?</strong><br />
Эта статья написана для программистов на C++, которые уже неплохо владеют самим языком, его основными конструкциями. В частности, необходимо знание, что такое ?аблоны(templates) и желателен опыт их использования. Также очень желательно знание стандартной библиотеки C++, так как многие примеры будут посвящены именно ей.</p>
<p><strong>Ну, поехали&#8230;</strong><br />
?так, приступим. Думаю, начать стоит с перевода термина traits. Обычно его переводят как &#171;свойства&#187;. Но traits реализуются классом, поэтому обычно употребляется термин &#171;класс свойств&#187;. Следует заметить, что свойства также можно реализовать с помощью структуры, так как в C++ это практически аналоги. Далее я буду использовать термин класс, хотя все сказанное будет в той же мере относиться к структурам.<span id="more-674"></span></p>
<p>Теперь следует дать определение свойств. Натан Майерс, разработав?ий метод использования свойств, предложил такое определение:<br />
Класс свойств &#8212; это класс, используемый вместо параметров ?аблона. В качестве класса он объединяет полезные типы и константы; как ?аблон, он является средством для обеспечения того &#171;дополнительного уровня косвенности&#187;, который ре?ает все проблемы программного обеспечения.</p>
<p>Определение не настолько понятное, так что давайте попробуем разобраться, что же имеется в виду. Для этого предлагается рассмотреть неболь?ой пример. В качестве примера мы рассмотрим ?аблонный класс динамического массива. Конечно, реализовывать полностью этот класс мы не будем(у нас уже есть vector), но общие концепции мы рассмотрим.<br />
?так, на? ?аблонный класс динамического массива должен иметь в качестве аргументов ?аблона:<br />
1) тип элемента ?аблона<br />
2) тип ссылки на элемент<br />
3) тип аргумента функций<br />
4) тип константной ссылки<br />
Думаю, прокомментировать стоит только тип аргумента функций. Этот тип используется для вставки элементов в массив. Например, эффективней передать int или char по значению, чем по константной ссылке.<br />
Тогда набросок класса будет выглядеть так:<br />
<code>template <typename T,<br />
          typename ArgT      = const T&#038;,<br />
          typename RefT      = T&#038;,<br />
          typename ConstRefT = const T&#038;><br />
class vector {<br />
     // ...<br />
    public:<br />
     typedef T             value_type;<br />
     typedef ArgT          arg_type;<br />
     typedef RefT          reference;<br />
     typedef ConstRefT     const_reference;</p>
<p>        void push_back(arg_type);</p>
<p>        // ...<br />
};</code></p>
<p>Для удобства были добавлены соответствующие значения параметров ?аблона по умолчанию.<br />
Тогда каждый пользователь на?его класса должен будет создавать объекты класса как-то так:<br />
<code>// используем параметры по умолчанию<br />
vector<int> vec1; // эквивалентно: vector<int, const int&#038;, int&#038;, const int&#038;></p>
<p>// переопределяем один из параметров по умолчанию<br />
// обратите на второй аргумент ?аблона(не ссылка, а передача по значению)<br />
vector<int, const int> vec2; // эквивалентно: vector<int, const int, int&#038;, const int&#038;></p>
<p>// переопределяем один из параметров по умолчанию<br />
vector<char, const char> vec3; // // эквивалентно: vector<char, const char, char&#038;, const char&#038;></p>
<p>// используем параметры по умолчанию<br />
vector<char> vec4; // эквивалентно: vector<char, const char&#038;, char&#038;, const char&#038;></code></p>
<p>Все хоро?о, все отлично работает. Но если мы захотим реализовать, например, связанный список, то нам придется для него задавать аналогичные параметры ?аблона. Это довольно муторно, так как придется каждый раз писать одно и то же. Тогда на помощь приходят классы свойств(traits). Создадим ?аблон класса, который будет содержать все те дополнительные аргументы ?аблона:<br />
<code>// первичный ?аблон<br />
// подходит в общем случае - аналог аргументов ?аблона по умолчанию<br />
template <typename T><br />
class elem_traits {<br />
    public:<br />
     typedef const T&#038; arg_type;<br />
     typedef       T&#038; reference;<br />
     typedef const T&#038; const_reference;<br />
};</code></p>
<p>Это и будет на? класс свойств. То есть он описывает те типы(arg_type, reference, const_reference), которые представляют на? тип T. Таким образом, нам надо вместо несколько аргументов ?аблона писать только один дополнительный аргумент &#8212; класс свойств, который содержит в себе все нужные типы.<br />
Тогда класс на?его динамического массива можно переписать так:<br />
<code>template <typename T,<br />
          typename traits = elem_traits<T> > // свойство по умолчанию<br />
class vector {<br />
     // ...<br />
    public:<br />
     typedef T                                value_type;<br />
     typedef typename traits::arg_type        arg_type;<br />
     typedef typename traits::reference       reference;<br />
     typedef typename traits::const_reference const_reference;</p>
<p>        void push_back(arg_type);</p>
<p>        // ...<br />
};</code></p>
<p>Тогда давайте посмотрим, как пользователи на?его динамического массива будут создавать объекты:<br />
// используется аргумент-свойство по умолчанию<br />
vector<int> vec1; // эквивалентно: vector<int, elem_traits<int> ><br />
// тогда:<br />
// arg_type  = const int&#038;<br />
// reference = int&#038;<br />
// const_reference = const int&#038;</p>
<p>// используется аргумент-свойство по умолчанию<br />
<code>vector<char> vec1; // эквивалентно: vector<char, elem_traits<char> ><br />
// тогда:<br />
// arg_type  = const char&#038;<br />
// reference = char&#038;<br />
// const_reference = const char&#038;</code></p>
<p>В этом примере для всех типов используются аргументы по умолчанию. Но мы выяснили, что аргументы типа char луч?е передавать не по константной ссылке, а по значению, то можно сделать специализацию на?его класса свойств:<br />
<code>// специализация для типа char<br />
template <><br />
class elem_traits<char> {<br />
    public:<br />
     typedef const char  arg_type; // определили тип, который передает по значению типы char<br />
     typedef       char&#038; reference;<br />
     typedef const char&#038; const_reference;<br />
};</code></p>
<p>Тогда объекты на?его динамического массива будем создавать так:<br />
<code>vector<std::string> vec1; // эквивалентно: vector<std::string, elem_traits<std::string> ><br />
// для всех типов, для которых не сделана специализация,<br />
// все остается как прежде:<br />
// тогда:<br />
// arg_type  = const std::string&#038; (по ссылке)<br />
// reference = std::string&#038;<br />
// const_reference = const std::string&#038;</p>
<p>// а для типа char мы сделали специализацию<br />
vector<char> vec2; // эквивалентно: vector<char, elem_traits<char> ><br />
// тогда:<br />
// arg_type  = const char (по значению, а не по ссылке)<br />
// reference = char&#038;<br />
// const_reference = const char&#038;</code></p>
<p>Давайте теперь рассмотрим случай, когда мы хотим создать динамический массив с элементами типа char, но чтобы arg_type был эквивалентен char&#038;. Специализация на?его класса elem_traits для char уже существует, то есть ее сделать мы уже не можем. В таком случае остается создать новый класс свойств:<br />
<code>// обратите внимание: структура, а не класс<br />
// (разницы никакой, это ли?ний раз подчеркивается данным примером)<br />
struct char_elem_traits {<br />
 // здесь переопределеяем тип аргумента функций.<br />
 // Мы договорились, что это будет char&#038;<br />
    typedef       char&#038; arg_type; // определили тип, который передает по ссылке типы char</p>
<p>    // остальное оставляем так же.<br />
    // Хотя ничто не ме?ает нам переопределеить тип ссылки или константной ссылки<br />
    typedef       char&#038; reference;<br />
    typedef const char&#038; const_reference;<br />
};</code></p>
<p>Тогда осталось только создать нужный динамический массив:<br />
<code>vector<char, char_elem_traits> vec;<br />
// тогда:<br />
// arg_type  = char&#038; (по ссылке, но не по константной)<br />
// reference = char&#038;<br />
// const_reference = const char&#038;</code></p>
<p>Но заметим, что класс(структура) char_elem_traits переопределяет только один тип &#8212; arg_type, а остальные остаются неимзенными по отно?ению к elem_traits<char>. То есть мы произвели ли?нюю работу, определив самостоятельно типы reference и const_reference. Хоро?о еще, что тут немного типов, а представьте, что их было бы около 20? 50? Чтобы каждый раз не переписывать общие свойства, можно воспользоваться открытым наследованием и переопределить нужные нам типы:<br />
<code>class char_elem_traits : public elem_traits<char> {<br />
 public:<br />
  typedef char&#038; arg_type; // определили тип, который передает по ссылке типы char</p>
<p>  // типы reference и const_reference наследуются<br />
};</code></p>
<p>Теперь можно использовать на? класс свойств char_elem_traits точно так же, как мы делали это рань?е.</p>
<p>До этого мы рассматривали только свойства, определяющие необходимые типы. Еще могут быть свойства-значения: они предоставляют нужные константы для данного типа.<br />
Рассмотрим пример: нам надо написать ?аблон класса, которому для каждого параметра ?аблона(типа) требуются связанные с ним константы. Первая мысль будет такой(пример немного перефразирован из вопроса с форума):<br />
<code>template <typename T,<br />
          std::size_t T2 = sizeof(T) * 4,<br />
          std::size_t T3 = sizeof(T) * 2,<br />
          std::size_t T4 = sizeof(T)<br />
          // ...<br />
          ><br />
class X {<br />
  // используем нужные константы<br />
  // T2 == sizeof(T) * 4<br />
  // T4 == sizeof(T)<br />
};</p>
<p>Но мы теперь люди продвинутые и знаем, как избежать такого боль?ого количества аргументов ?аблона - обернуть все в traits:<br />
template <typename T><br />
struct x_traits {<br />
 static std::size_t T2 = sizeof(T) * 4;<br />
 static std::size_t T3 = sizeof(T) * 2;<br />
 static std::size_t T4 = sizeof(T);<br />
};</p>
<p>template <typename T, typename traits = x_traits<T> ><br />
class X {<br />
  // используем нужные константы через traits:<br />
  // traits::T2 == sizeof(T) * 4<br />
  // traits::T4 == sizeof(T)<br />
};</p>
<p>Но теперь в на?ем коде возникает проблема: если вдруг получится так, что пользователь на?его класса захочет взять адрес на?ей константы, компилятор должен будет создать реальную константу в памяти, адрес которой можно взять. Для этого был предуман трюк с enum'ом:<br />
template <typename T><br />
struct x_traits {<br />
 enum { T2 = sizeof(T) * 4 };<br />
 enum { T3 = sizeof(T) * 2 };<br />
 enum { T4 = sizeof(T)      };<br />
};</p>
<p>template <typename T, typename traits = x_traits<T> ><br />
class X {<br />
  // используем нужные константы через traits:<br />
  // traits::T2 == sizeof(T) * 4<br />
  // traits::T4 == sizeof(T)<br />
};</code></p>
<p>Дело в том, что компилятор не позволяет взять адрес enum-констант. Так что мы теперь точно знаем, что на?а константа будет вставлена в код числом.<br />
На данном этапе все хоро?о. Но вдруг нам надо доработать класс так, что нужна константа вещественного типа. Но возникает такая проблема: в классах можно инициализировать только статические интегральные константы. В enum&#8217;ах тоже можно использовать только целые типы. Что же тогда делать? Остается только определить inline-фунцию, которая бы возвращала нужное значение:<br />
<code>template <typename T><br />
struct x_traits {<br />
 static std::size_t T2() {<br />
  return(sizeof(T) * 4);<br />
 }</p>
<p> static std::size_t T3() {<br />
  return(sizeof(T) * 2);<br />
 }</p>
<p> static std::size_t T4() {<br />
  return(sizeof(T));<br />
 }</p>
<p> // возвращаемое значение типа double<br />
 static double T5() {<br />
  return(sizeof(T) * 5 / 7);<br />
 }<br />
};</p>
<p>template <typename T, typename traits = x_traits<T> ><br />
class X {<br />
  // используем нужные константы через traits:<br />
  // T2: traits::T2() - возвращает тип std::size_t, можно и через enum<br />
  // T5: traits::T5() - возвращает тип double, по-другому не сделать, только функция<br />
};</code></p>
<p>Надо заметить, что наличие функции на производительность не влияет, так как современные компиляторы способны подставить нужное значение прямо в код вместо вызова функции. Также можно сочетать наличие функций, возвращающих нужные значения вещественного типа, и простые интегральные константы, полученные с помощью enum.</p>
<p>Теперь мы знаем основные принципы для работы с traits. Так что давайте рассмотрим пример, который помогает рас?ирить стандартную библиотеку C++.<br />
Давайте рассмотрим такую задачу(перефразировано из вопроса с форума):<br />
Цитата<br />
Я хочу определить размер файла с помощь класса ifstream. Сам файл весит боль?е 5 Гб. Функция tellg() возвращает какое-то нереальное значение. Как можно правильно определить размер файла? </p>
<p>На данный момент все известные мне версии стандартной библиотеки C++ представляют позицию в файле 32-разрядным целым. Но дело в том, что обычные 32-разрядные целые числа не могут представлять размер файла, боль?его 4 ГБ(происходит переполнение). То есть нам надо каким-либо образом заставить стандартную библиотеку использовать не 32-разрядные числа, а, например 64-разрядные(или вообще на? собственный тип(класс), который мы опи?ем). Как это сделать? Как вы уже догадались, помогут нам traits.<br />
Как известно, ifstream &#8212; это только typedef от класса basic_ifstream. Сам же класс basic_ifstream принимает 2 параметра ?аблона: первый из них определяет тип символа, а второй определяет свойста(traits). Так вот эти свойста и должны определять, каким типом представлять позицию в файле, как сравнивать символы и тд. Второй параметр ?аблона класса basic_ifstream по умолчанию будет классом char_traits. Это стандартный класс, который описывает основные свойста: нужные типы, как сравнивать символы, присваивать и тд.. Так как мы не собираемся переопределять это все(нам надо заменить только 2 типа), тогда хоро?ей идеей будет унаследоваться от класса char_traits.<br />
У класса char_traits есть 2 интересующих нас типа(полный список типов можно найти в документации):<br />
1) pos_type &#8212; тип, используемый для представления позиции в потоке<br />
2) off_type &#8212; тип, используемый для представления смещений между позициями в потоке<br />
Вот их-то как раз нам и надо переопределить. Давайте сделаем первую попытку:</p>
<p><code>template <typename char_t><br />
struct long_pointer_traits : public std::char_traits<char_t> {<br />
 typedef __int64 pos_type;<br />
 typedef __int64 off_type;<br />
};</p>
<p>typedef std::basic_ifstream<char, long_pointer_traits<char> > long_ifstream;</p>
<p>// используем long_ifstream</code></p>
<p>Но вот незадача: этот код не компилируется. Дело в том, что pos_type должен уметь конструироваться из нескольких заранее определенных типов(как показало исследование, 2). Базовые типы этого делать не умеют, так что придется написать свой собственный класс. Я не буду заострять внимание на этом классе, так как статья немного не на эту тему. Я просто приведу реализацию этого класса, а если у вас будут какие-то вопросы, то писать либо здесь, либо в PM. ?так, вот код:<br />
<code>// пространство имен, в которое заносятся детали реализации<br />
namespace detail {<br />
 template <typename num_type, typename state_type = std::mbstate_t><br />
 class pos_type_t {<br />
     typedef pos_type_t<num_type, state_type> my_type;</p>
<p>     num_type    m_pos;<br />
     state_type  m_state;</p>
<p>     static state_type initial_state;</p>
<p>    public:<br />
    // конструкторы<br />
     pos_type_t(std::streampos off) : m_pos(off), m_state(initial_state) {}<br />
        pos_type_t(num_type off = 0) : m_pos(off), m_state(initial_state) {}<br />
        pos_type_t(state_type state, num_type pos) : m_pos(pos), m_state(state) {}</p>
<p>        // получение состояния потока<br />
        state_type state() const {<br />
            return(m_state);<br />
        }</p>
<p>        // установка состояния потока<br />
        void state(state_type st) {<br />
            m_state = st;<br />
        }</p>
<p>        // получение позиции<br />
        num_type seekpos() const    {<br />
        return(m_pos);<br />
        }</p>
<p>        // оператор преобразования<br />
        operator num_type() const {<br />
        return(m_pos);<br />
        }</p>
<p>        // далее идут операторы, которые осуществляют арифметические операции</p>
<p>        num_type operator- (const my_type&#038; rhs) const {<br />
    return(static_cast<num_type>(*this) - static_cast<num_type>(rhs));<br />
        }</p>
<p>        my_type&#038; operator+= (num_type pos) {<br />
            m_pos += pos;<br />
            return(*this);<br />
        }</p>
<p>        my_type&#038; operator-= (num_type pos) {<br />
            m_pos -= pos;<br />
            return(*this);<br />
        }</p>
<p>        my_type operator+ (num_type pos) const {<br />
            my_type tmp(*this);<br />
            return(tmp += pos);<br />
        }</p>
<p>        my_type operator- (num_type pos) const {<br />
            my_type tmp(*this);<br />
            return(tmp -= pos);<br />
        }</p>
<p>        // операторы сравнения</p>
<p>        bool operator== (const my_type&#038; rhs) const {<br />
    return(static_cast<num_type>(*this) == static_cast<num_type>(rhs));<br />
        }</p>
<p>        bool operator!= (const my_type&#038; rhs) const {<br />
    return(!(*this == rhs));<br />
        }<br />
 };<br />
//---------------------------------------------------<br />
 // статическая константа, которая обозначает начальное состояние<br />
 template <typename num_type, typename state_type><br />
 state_type pos_type_t<num_type, state_type>::initial_state;<br />
}<br />
//---------------------------------------------------<br />
// наконец-то на? класс свойств:<br />
template <typename char_t, typename long_pos_t><br />
struct long_pointer_traits : public std::char_traits<char_t> {<br />
 // определение pos_type через на? только что написанный класс<br />
 typedef detail::pos_type_t<long_pos_t> pos_type;</p>
<p> // определение off_type через тип, переданный во 2 аргументе ?аблона<br />
 typedef long_pos_t off_type;<br />
};<br />
//---------------------------------------------------<br />
// вводим тип "длинного" файла<br />
typedef std::basic_ifstream<char, long_pointer_traits<char, __int64> > long_ifstream;</p>
<p>// используем long_ifstream для получения размера файла</code></p>
<p>ОК, теперь все компилируется и работает. Но кроме получения позиции в файле, нам обычно надо работать еще с этими файлами(читать, писать). ?, конечно, нам приходится работать со строками. Тогда если мы попытаемся считать строку из файла таким образом:<br />
<code>long_ifstream infile(strFileName, std::ios::binary);<br />
std::string res;<br />
std::getline(infile, res);</code></p>
<p>То мы получим о?ибку компиляции. Проблема в том, что std::string &#8212; это &#171;всего ли?ь&#187; typedef от std::basic_string. Этот класс принимает 2 параметра ?аблона: первый &#8212; тип для представления символа, а второй(как вы уже, наверное, догадались) &#8212; traits. Так вот, для корректной работы нам надо определить и свой тип строки:<br />
<code>// "длинные" типы:<br />
typedef std::basic_ifstream<char, long_pointer_traits<char, __int64> >  long_ifstream;<br />
typedef std::basic_string<char, long_pointer_traits<char, __int64> >    long_string;</p>
<p>long_ifstream infile(strFileName, std::ios::binary);<br />
long_string res;<br />
std::getline(infile, res);</code></p>
<p>Теперь все работает прекрасно. Таким образом, для правильного взаимодействия компонентов стандартной библиотеки нам придется определять нужные типы и работать с ними. К сожалению, на данный момент я не знаю способа, как можно было бы создать нужный тип для стандартных потоков ввода/вывода(cin, cout, cerr, clog). Так что чтобы вывести такую &#171;длинную&#187; строку на экран, надо будет написать свой оператор вывода такой строки. Другого ре?ения мне неизвестно(если кто-то знает &#8212; поделитесь, буду признателен).<br />
Также хочу сказать несколько слов о совместимости и переносимости: приведенный мной код по определению размера боль?ого файла был проверен на компиляторах VC7.1 и Intel C++ 8.0. ?спользовалась стандартная библиотека, которая идет по умолчанию с VC. При работе с ней замечено никаких о?ибок не было. Проверялся код и с использованием STLPort версий 4.6.2 и 5.0. Компилировался он без проблем, но работал неправильно. Надеюсь, в дальней?их версиях STLPort&#8217;а это будет исправлено и работать будет корректно, так как данный код соответствует стандарту.</p>
<p>Ну вот, вроде бы и все, что я хотел сообщить по поводу свойств. Надеюсь, данная статья помогла вам разобраться, что это такое и зачем оно надо. Также жду ва?и отзывы, комментарии и критику.</p>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/chto-takoe-traits.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Списки и последовательный доступ в C++</title>
		<link>http://about-programming.ru/spiski-i-posledovatelnyj-dostup-v-c.html</link>
		<comments>http://about-programming.ru/spiski-i-posledovatelnyj-dostup-v-c.html#comments</comments>
		<pubDate>Tue, 14 Dec 2010 13:43:41 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=671</guid>
		<description><![CDATA[Список как структура для хранения данных известна достаточно ?ироко. Фактически, наверняка в любом курсе программирования ее изучают в том или ином виде. Но то, что обычно усваивает студент (читать: &#171;будущий программист&#187;) заключается примерно в следующем: Списки организуются на динамической памяти. Динамическая память, по мнению студента, это то, что можно получить при помощи операторов new и [...]]]></description>
			<content:encoded><![CDATA[<p>Список как структура для хранения данных известна достаточно ?ироко. Фактически, наверняка в любом курсе программирования ее изучают в том или ином виде. Но то, что обычно усваивает студент (читать: &#171;будущий программист&#187;) заключается примерно в следующем: </p>
<p><strong>Списки</strong> организуются на динамической памяти. Динамическая память, по мнению студента, это то, что можно получить при помощи операторов new и удалить dispose. </p>
<p><strong>Списки</strong> организуются при помощи одного указателя на голову списка и, включенных в каждый элемент, указателей на следующий элемент списка. Точнее, может присутствовать указатель и на предыдущий элемент, а также указатель на хвост списка, это не суть важно.<span id="more-671"></span> </p>
<p>Кроме этого, средний студент часто путает список с очередью: все дело в том, что обычно на лабораторных работах дается задание реализовать очередь, выбрав для ее внутреннего устройства список. На самом деле, очередь это &#171;нечто&#187;, что позволяет поместить туда элемент и получить его согласно правилу FIFO (&#171;First In, First Out&#187; &#8212; &#171;Первый во?ел, первый вы?ел&#187;). </p>
<p>Тем не менее, я не хотел обижать студентов, совсем нет. Просто очень часто, если практически не постоянно можно увидеть один и тот же подход: организацию списков при помощи указателей. Проблема заключается в том, что такая реализация списков не единственна и достаточно часто не эффективна. </p>
<p>Допустим, программист реализует некую структуру данных, основываясь на хе?-таблице, при этом коллизии ре?аются списками элементов. Что может сделать программист, имеющий стереотипы наподобие предыдущих? Что-нибудь в духе: </p>
<p><code>#include <stdio.h></p>
<p>#include <stdlib.h></p>
<p>#include <string.h></p>
<p>#include <time.h></p>
<p>struct hash_list</p>
<p>{</p>
<p>int key;</p>
<p>hash_list* next;</p>
<p>};</p>
<p>#define HASH_TABLE_SIZE 511</p>
<p>hash_list* hash[HASH_TABLE_SIZE];</p>
<p>#define COUNT 1000000</p>
<p>struct {</p>
<p>unsigned int iterations;</p>
<p>} stat;</p>
<p>int main()</p>
<p>{</p>
<p>unsigned int i, j;</p>
<p>int k;</p>
<p>hash_list* ptr, *prev_ptr;</p>
<p>bzero((char*)hash, sizeof(hash));</p>
<p>bzero((char*)&#038;stat, sizeof(stat));</p>
<p>srandom(time(NULL));</p>
<p>for(i = 0; i < COUNT; i++)</p>
<p>{</p>
<p>k = random() &#038; 8191;</p>
<p>prev_ptr = NULL;</p>
<p>for(ptr = hash[k%HASH_TABLE_SIZE]; </p>
<p>ptr &#038;&#038; ptr->key != k; </p>
<p>prev_ptr = ptr, ptr = ptr->next, stat.iterations++)<br />
;</p>
<p>if(!ptr)</p>
<p>{</p>
<p>if(prev_ptr)</p>
<p>{</p>
<p>prev_ptr->next = (hash_list*)calloc(1, sizeof(hash_list));</p>
<p>prev_ptr->next->key = k;</p>
<p>}</p>
<p>else</p>
<p>{</p>
<p>hash[k%HASH_TABLE_SIZE] = (hash_list*)calloc(1, sizeof(hash_list));</p>
<p>hash[k%HASH_TABLE_SIZE]->key = k;</p>
<p>}</p>
<p>}</p>
<p>}</p>
<p>printf("Iterations: %u\n", stat.iterations);</p>
<p>}</code></p>
<p>Что же тут неправильного? Ничего. Все сделано, вроде бы, достаточно логично. Тем не менее, показательно сделать несколько запусков и полюбоваться результатами (для измерения затраченного времени буду использовать команду bash time): </p>
<p><code>alk:~$ g++ -O5 t1.cpp -o t1</p>
<p>alk:~$ time t1</p>
<p>Iterations: 7485181</p>
<p>real 0m0.559s</p>
<p>user 0m0.549s</p>
<p>sys 0m0.001s</p>
<p>alk:~$ time t1</p>
<p>Iterations: 7485586</p>
<p>real 0m0.556s</p>
<p>user 0m0.555s</p>
<p>sys 0m0.001s</p>
<p>alk:~$ time t1</p>
<p>Iterations: 7486098</p>
<p>real 0m0.558s</p>
<p>user 0m0.549s</p>
<p>sys 0m0.001s</p>
<p>alk:~$ time t1</p>
<p>Iterations: 7480581</p>
<p>real 0m0.556s</p>
<p>user 0m0.548s</p>
<p>sys 0m0.000s</code></p>
<p>На самом деле, единственное что можно поставить в упрек написанной вы?е программе, это расход на каждый элемент (целое число) два раза боль?е оперативной памяти, чем надо еще столько же тратится на указатель для организации списка. Несложно придумать реализацию подобного списка на массиве, когда указатели не нужны: </p>
<p><code>#include <stdio.h></p>
<p>#include <stdlib.h></p>
<p>#include <string.h></p>
<p>#include <time.h></p>
<p>struct hash_item</p>
<p>{</p>
<p>int* keys;</p>
<p>size_t alloc;</p>
<p>size_t used;</p>
<p>};</p>
<p>#define HASH_TABLE_SIZE 511</p>
<p>#define HASH_ALLOC_DELTA 16</p>
<p>hash_item hash[HASH_TABLE_SIZE];</p>
<p>#define COUNT 1000000</p>
<p>struct {</p>
<p>unsigned int iterations;</p>
<p>} stat;</p>
<p>int main()</p>
<p>{</p>
<p>unsigned int i, j;</p>
<p>int k;</p>
<p>hash_item* ptr;</p>
<p>bzero((char*)hash, sizeof(hash));</p>
<p>bzero((char*)&#038;stat, sizeof(stat));</p>
<p>srandom(time(NULL));</p>
<p>for(i = 0; i < COUNT; i++)</p>
<p>{</p>
<p>k = random() &#038; 8191;</p>
<p>ptr = hash + (k%HASH_TABLE_SIZE);</p>
<p>for(j = 0; j < ptr->used &#038;&#038; ptr->keys[j] != k; </p>
<p>j++, stat.iterations++)</p>
<p>;</p>
<p>if(j >= ptr->used)</p>
<p>{</p>
<p>if(ptr->used == ptr->alloc)</p>
<p>{</p>
<p>int* temp = ptr->keys;</p>
<p>ptr->keys = (int*)calloc(ptr->alloc += HASH_ALLOC_DELTA, </p>
<p>sizeof(int));</p>
<p>if(ptr->used) </p>
<p>{</p>
<p>memcpy(ptr->keys, temp, ptr->used*sizeof(int));</p>
<p>free(temp);</p>
<p>}</p>
<p>}</p>
<p>ptr->keys[ptr->used++] = k;</p>
<p>}</p>
<p>}</p>
<p>printf("Iterations: %u\n", stat.iterations);</p>
<p>}</code></p>
<p>Выглядит на первый взгляд несколько сомнительно: ведь преимущества обычных списков с указателями заключаются как раз в том, что общее количество выделенных элементов будет равно нужному, а при вставке нового элемента не требуется модификация всего остального списка. В данном же случае, количество выделенных элементов, размер которых, правда, мень?е предыдущего в два раза, всегда кратно 16, а изменение списка влечет за собой копирование всех данных из старой области памяти в новую. </p>
<p>Тем не менее, надо попробовать еще раз запустить тест: </p>
<p><code>alk:~$ g++ -O5 t2.cpp -o t2</p>
<p>alk:~$ time t2</p>
<p>Iterations: 7478165</p>
<p>real 0m0.296s</p>
<p>user 0m0.296s</p>
<p>sys 0m0.000s</p>
<p>alk:~$ time t2</p>
<p>Iterations: 7477196</p>
<p>real 0m0.296s</p>
<p>user 0m0.296s</p>
<p>sys 0m0.000s</p>
<p>alk:~$ time t2</p>
<p>Iterations: 7489060</p>
<p>real 0m0.296s</p>
<p>user 0m0.295s</p>
<p>sys 0m0.000s</p>
<p>alk:~$ time t2</p>
<p>Iterations: 7492167</p>
<p>real 0m0.298s</p>
<p>user 0m0.282s</p>
<p>sys 0m0.008s</code></p>
<p>Если вас не удивили полученные числа, то читать даль?е вам будет совер?енно неинтересно. </p>
<p>Стоит отметить, что общее количество сравнений практически одинаково в обоих случаях. Разница в затраченном времени между вторым и первым вариантом программы достаточно просто объяснима, для этого достаточно представлять себе в общих чертах устройство современных микропроцессоров. </p>
<p>Все дело в том, что память не является чем-то однородным, более того, память образует иерархию по своей скорости, например: регистры процессора, ке? первого уровня, ке? второго уровня, оперативная память, жесткие диски&#8230; несмотря на то, что каждый &#171;вид&#187; памяти предназначен, по сути, для одного и того же &#8212; хранения данных &#8212; скорость доступа может сильно отличаться.<br />
Когда процессор желает что-то прочитать из оперативной памяти, эти данные &#171;оседают&#187; в ке?ах, доступ к которым быстрее, и если через некоторое время (пока запись еще не была удалена из ке?ей) процессор вновь обратится к тому же адресу, что и рань?е, то обращения к относительно медленной оперативной памяти не будет. Кроме того, ке? разбит на области фиксированного размера (линии, в случае обычного Пентиума &#8212; 32 байта), и именно такими блоками происходит чтение данных из оперативной памяти. Таким образом, если, как во втором случае, происходит чтение последовательного массива целых чисел, то считывая один элемент, в ке? попадут как минимум 8 элементов этого массива и все они боль?е не будут требовать обращений к оперативной памяти в ближай?ее время. </p>
<p>В случае же &#171;с указателями&#187;, невозможно предсказать какой элемент будет следующим в списке, потому что он зависит от содержимого внутри прочитанной области данных (указателя) и, скорее всего, следующий элемент не попадет в ке?. Поэтому итерация по списку будет требовать еще столько операции чтения из оперативной памяти, сколько будет в списке элементов. </p>
<p>Кроме того, современные умные микропроцессоры, или не менее умные оптимизаторы, умеют делать предварительное чтение данных в ке?. То есть, если читается блок в ке?, то пока процессор с ним работает, можно прочитать в ке? следующий блок памяти в расчете на последовательный доступ к данным (prefetch). Поэтому скорость последовательного доступа к элементам массива будет вы?е, чем доступ к элементам &#171;списка с указателями&#187; даже когда размер структур более размера целого числа. </p>
<p>Кстати сказать, в таких случаях выгодно выравнивать размер структур по размеру ке?лайнов, потому что чтение одного ке?лайна из оперативной памяти тоже операция неоднородная и начало ке?лайна появится в ке?е быстрее, чем окончание, на чем тоже можно &#171;сыграть&#187;. </p>
<p><strong>Резюме</strong><br />
Таким образом, процессор всегда рассчитывает на последовательный доступ к данным и использование этого факта может сильно ускорить работу программы. Это относится не только к организации списков на массивах (не в случае, когда указатели на следующий элемент заменяются индексами внутри массива, а когда положение элемента в списке определяется его индексом в массиве), но и, например, к обработке двумерных массивов (значительно выгоднее читать массив по возрастанию реальных адресов ячеек). </p>
<p><strong>PS:</strong> Кстати сказать, существуют эффективные вариации сортировки слиянием для данных, находящихся в оперативной памяти. Просто именно такой, достаточно простой способ сортировки, позволяет учитывать в алгоритме иерархичность оперативной памяти и легко распараллеливается на несколько процессоров.</p>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/spiski-i-posledovatelnyj-dostup-v-c.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Как обнаружить утечку памяти в C++</title>
		<link>http://about-programming.ru/kak-obnaruzhit-utechku-pamyati-v-c.html</link>
		<comments>http://about-programming.ru/kak-obnaruzhit-utechku-pamyati-v-c.html#comments</comments>
		<pubDate>Tue, 14 Dec 2010 13:37:08 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=669</guid>
		<description><![CDATA[Введение При разработке боль?их приложений, оперирующих боль?ими объемами информации на первое место при отладке встает проблема обнаружения неправильного распределения памяти. Суть проблемы состоит в том, что если мы выделили участок памяти, а затем освободили не весь выделенный объем, то образуются блоки памяти, которые помечены как занятые, но на самом деле они не используются. При длительной [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Введение </strong><br />
При разработке боль?их приложений, оперирующих боль?ими объемами информации на первое место при отладке встает проблема обнаружения неправильного распределения памяти. Суть проблемы состоит в том, что если мы выделили участок памяти, а затем освободили не весь выделенный объем, то образуются блоки памяти, которые помечены как занятые, но на самом деле они не используются. При длительной работе программы такие блоки могут накапливаться, приводя к значительному расходу памяти. <span id="more-669"></span></p>
<p>Для обнаружения подобных о?ибок создано специализированное программное обеспечение (типа BoundsChecker от Numega), однако чаще бывает удобнее встроить механизм обнаружения утечки в свои проекты. Поэтому метод должен быть простым, и в то же время как можно более универсальным. Кроме того, не хотелось бы переписывать годами накопленные мегабайты кода, написанного и отлаженного задолго до того, как вам при?ло в голову оградить себя от о?ибок. Так что к списку требований добавляется стандартизация, т.е. нужно каким-то образом встроить защиту от о?ибок в стандартный код. </p>
<p>Предлагаемое ре?ение основывается на перегрузке стандартных операторов распределения памяти new и delete. Причем перегружать мы будем глобальные операторы new|delete, т.к. переписать эти операторы для каждого разработанного ранее класса было бы очень трудоемким процессом. Т.о. после перегрузки нам нужно будет только отследить распределение памяти и, соответственно, освобождение ее в момент завер?ения программы. Все несоответствия &#8212; о?ибка. </p>
<p><strong>Реализация </strong><br />
Проект написан на Visual C++, но переписать его на любой другой диалект С++ не будет сли?ком сложной задачей. Во-первых, нужно переопределить стандартные операторы new и delete так, чтобы это работало во всех проектах. Поэтому в stdafx.h добавляем следующий фрагмент: </p>
<p><code>      #ifdef _DEBUG<br />
      inline void * __cdecl operator new(unsigned int size,<br />
                                         const char *file, int line)<br />
      {<br />
      };</p>
<p>      inline void __cdecl operator delete(void *p)<br />
      {<br />
      };<br />
      #endif</code></p>
<p>Как видите, переопределение операторов происходит в блоке #ifdef/#endif. Это ограждает на? код от влияния на релиз компилируемой программы. Вы, наверное, заметили, что теперь оператор new имеет три параметра вместо одного. Два дополнительных параметра содержат имя файла и номер строки, в которой выделяется память. Это удобно для обнаружения конкретного места, где происходит о?ибка. Однако код на?их проектов по-прежнему ссылается на оператор new, принимающий один параметр. Для исправления этого несоответствия нужно добавиить следующий фрагмент </p>
<p><code>      #ifdef _DEBUG<br />
      #define DEBUG_NEW new(__FILE__, __LINE__)<br />
      #else<br />
      #define DEBUG_NEW new<br />
      #endif<br />
      #define new DEBUG_NEW</code></p>
<p>Теперь все на?и операторы new будут вызываться с тремя параметрами, причем недостающие параметры подставит препроцессор. Конечно, пустые переопределенные функции ни в чем нам не помогут, так что давайте добавим в них какой-нибудь код: </p>
<p><code>      #ifdef _DEBUG<br />
      inline void * __cdecl operator new(unsigned int size,<br />
                                         const char *file, int line)<br />
      {<br />
	      void *ptr = (void *)malloc(size);<br />
	      AddTrack((DWORD)ptr, size, file, line);<br />
	      return(ptr);<br />
      };<br />
      inline void __cdecl operator delete(void *p)<br />
      {<br />
	      RemoveTrack((DWORD)p);<br />
	      free(p);<br />
      };<br />
      #endif</code></p>
<p>Для полноты картины нужно переопределить операторы new[] и delete[], однако никаких существенных отличий здесь нет &#8212; творите! </p>
<p>Последний ?трих &#8212; пи?ем функции AddTrack() и RemoveTrack(). Для создания списка используемых блоков памяти будем использовать стандартные средства STL: </p>
<p><code>      typedef struct {<br />
	      DWORD	address;<br />
	      DWORD	size;<br />
	      char	file[64];<br />
	      DWORD	line;<br />
      } ALLOC_INFO;</p>
<p>      typedef list[block]0[/block]address = addr;<br />
	      strncpy(info->file, fname, 63);<br />
	      info->line = lnum;<br />
	      info->size = asize;<br />
	      allocList->insert(allocList->begin(), info);<br />
      };</p>
<p>      void RemoveTrack(DWORD addr)<br />
      {<br />
	      AllocList::iterator i;</p>
<p>	      if(!allocList)<br />
		      return;<br />
	      for(i = allocList->begin(); i != allocList->end(); i++)<br />
	      {<br />
		      if((*i)->address == addr)<br />
		      {<br />
			      allocList->remove((*i));<br />
			      break;<br />
		      }<br />
	      }<br />
      };</code></p>
<p>Перед самым завер?ением программы на? список allocList содержит ссылки на блоки памяти, котороые не были освобождены. Все, что нужно сделать &#8212; вывести эту информацию куда-нибудь. В на?ем проекте мы выведем список неосвобожденных участков памяти в окно вывода отладочных сообщений Visual C++: </p>
<p><code>   void DumpUnfreed()<br />
   {<br />
	   AllocList::iterator i;<br />
	   DWORD totalSize = 0;<br />
	   char buf[1024];</p>
<p>      if(!allocList)<br />
	      return;</p>
<p>      for(i = allocList->begin(); i != allocList->end(); i++) {<br />
	      sprintf(buf, "%-50s:\t\tLINE %d,\t\tADDRESS %d\t%d unfreed\n",<br />
		      (*i)->file, (*i)->line, (*i)->address, (*i)->size);<br />
	      OutputDebugString(buf);<br />
	      totalSize += (*i)->size;<br />
      }<br />
      sprintf(buf, "--------------------------------------------------\n");<br />
      OutputDebugString(buf);<br />
      sprintf(buf, "Total Unfreed: %d bytes\n", totalSize);<br />
      OutputDebugString(buf);<br />
   };</code></p>
<p>Надеюсь, этот проект сделает ва?и баг-листы короче, а программы устойчивее. Удачи! </p>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/kak-obnaruzhit-utechku-pamyati-v-c.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Как узнать IP и MAC адрес своего компьютера на C++</title>
		<link>http://about-programming.ru/%d0%ba%d0%b0%d0%ba-%d1%83%d0%b7%d0%bd%d0%b0%d1%82%d1%8c-ip-%d0%b8-mac-%d0%b0%d0%b4%d1%80%d0%b5%d1%81-%d1%81%d0%b2%d0%be%d0%b5%d0%b3%d0%be-%d0%ba%d0%be%d0%bc%d0%bf%d1%8c%d1%8e%d1%82%d0%b5%d1%80%d0%b0.html</link>
		<comments>http://about-programming.ru/%d0%ba%d0%b0%d0%ba-%d1%83%d0%b7%d0%bd%d0%b0%d1%82%d1%8c-ip-%d0%b8-mac-%d0%b0%d0%b4%d1%80%d0%b5%d1%81-%d1%81%d0%b2%d0%be%d0%b5%d0%b3%d0%be-%d0%ba%d0%be%d0%bc%d0%bf%d1%8c%d1%8e%d1%82%d0%b5%d1%80%d0%b0.html#comments</comments>
		<pubDate>Mon, 04 Jan 2010 19:33:08 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[IP адрес]]></category>
		<category><![CDATA[MAC адрес]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=591</guid>
		<description><![CDATA[Как узнать IP и MAC адрес моего компа в сети на C++ Для определения мы будем пользоваться функциями gethostname и gethostbyname из библиотеки winsock.h. Если у вас два и более сетевых подключений, программа покажет IP адрес первого в очереди. #include &#60;winsock.h&#62; #include &#60;windows.h&#62; int main (int argc, char* argv[]) { const int WSVer = 0×101; [...]]]></description>
			<content:encoded><![CDATA[<h3>Как узнать IP и MAC адрес моего компа в сети на C++</h3>
<p>Для определения мы будем пользоваться функциями <strong>gethostname</strong> и <strong>gethostbyname</strong> из библиотеки <strong>winsock.h.</strong> Если у вас два и более сетевых подключений, программа покажет <strong>IP адрес</strong> первого в очереди.<span id="more-591"></span></p>
<blockquote><p><strong>#include &lt;winsock.h&gt;<br />
#include &lt;windows.h&gt;</strong></p>
<p><strong>int main (int argc, char* argv[])<br />
{<br />
const int WSVer  =  0×101;<br />
WSAData wsaData;<br />
hostent *h;<br />
char Buf[128];<br />
if  (WSAStartup (WSVer,  &amp;wsaData)  ==  0)<br />
{<br />
if (gethostname (&amp;Buf[0],  128)  ==  0)<br />
{<br />
h = gethostbyname (&amp;Buf[0]);<br />
if  (h  !=  NULL)      MessageBox (0,inet_ntoa (*(reinterpret_cast&lt;in_addr *&gt;(*(h-&gt;h_addr_list)))),0,0);<br />
else             MessageBox (0,&#187;Вы не в сети. ? IP адреса у вас нет.&#187;,0,0);<br />
}<br />
WSACleanup;<br />
}<br />
return 0;<br />
}</strong></p></blockquote>
<p>Также можно воспользоваться WinAPI функцией <strong>GetAdaptersInfo</strong>. Она тебе вернет информацию по всем сетевым адаптерам системы.WinAPI фукнции очень полезная вещь, рекомендую тебе почаще листать справочник.</p>
<p><strong><a href="http://about-programming.ru/ccc/591.html">Узнать MAC адрес</a></strong> можно как предыдущим способом, с помощью <strong>GetAdaptersInfo</strong>. Но также и другим:</p>
<blockquote><p><strong>#include &lt;stdio.h&gt;<br />
#include &lt;windows.h&gt;<br />
#include &lt;Winsock2.h&gt;<br />
#include &lt;Iphlpapi.h&gt;</strong></p>
<p><strong>///&#8212;&#8212;&#8212; cpp-файл &#8212;&#8212;&#8212;- </strong></p>
<p><strong>#include «stdafx.h»<br />
char ip[]=&#187;192.168.100.1&#8243;;</strong></p>
<p><strong>int main (int argc, char* argv[])<br />
{<br />
//Будем использовать сокеты<br />
WSADATA WsaData;<br />
DWORD _ip=inet_addr (ip);<br />
if (WSAStartup (0×0202, &amp;WsaData)==NULL)<br />
printf («WSA Starup OK!\n»);</strong></p>
<p><strong>//Создаём UDP-сокет и отсылаем по нему любые данные<br />
SOCKET udp_s;<br />
SOCKADDR_IN udp_sin;<br />
udp_s=socket (AF_INET, SOCK_DGRAM, IPPROTO_UDP);<br />
if (udp_s!=SOCKET_ERROR)<br />
{<br />
udp_sin.sin_family = AF_INET;<br />
udp_sin.sin_port = htons (5232); //Шлём на любой порт.<br />
udp_sin.sin_addr.s_addr = _ip;<br />
if (sendto (udp_s, «TEST», 5, NULL, (SOCKADDR*)&amp;udp_sin, sizeof (udp_sin))&gt;0)<br />
{ //Пакет отослан. Вытаскиваем MAC-адрес из системы<br />
MIB_IPNETTABLE * pIpNetTable = (MIB_IPNETTABLE *) new char[0xFFFF];<br />
ULONG cbIpNetTable = 0xFFFF;<br />
if (NO_ERROR == GetIpNetTable (pIpNetTable, &amp;cbIpNetTable, TRUE))<br />
{<br />
for (DWORD i = 0; i &lt; pIpNetTable-&gt;dwNumEntries; i++)<br />
{<br />
if (pIpNetTable-&gt;table[i].dwAddr == _ip&amp;&amp;pIpNetTable-&gt;table[i].dwType != 2)<br />
{<br />
printf («IP:%s MAC:%X-%X-%X-%X-%X-%X\n», ip,<br />
pIpNetTable-&gt;table[i].bPhysAddr[0],<br />
pIpNetTable-&gt;table[i].bPhysAddr[1],<br />
pIpNetTable-&gt;table[i].bPhysAddr[2],<br />
pIpNetTable-&gt;table[i].bPhysAddr[3],<br />
pIpNetTable-&gt;table[i].bPhysAddr[4],<br />
pIpNetTable-&gt;table[i].bPhysAddr[5]);<br />
delete[] pIpNetTable;<br />
closesocket (udp_s);<br />
WSACleanup ();<br />
return 0;<br />
}<br />
}<br />
printf («MAC-address not found\n»);<br />
delete[] pIpNetTable;<br />
}<br />
else printf («ERROR Open IPMAC table\n»);<br />
}<br />
else printf («Send data ERROR!\n»);</strong></p>
<p><strong>closesocket (udp_s);<br />
}<br />
else printf («ERROR open socket\n»);</strong></p>
<p><strong>WSACleanup ();         //Освобождаем ресурсы<br />
return 0;<br />
}</strong>﻿</p></blockquote>
<p>Мой блог находят по следующим фразам</p>
<ul>
<li><a href="http://about-programming.ru">Все о программировании</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/php.html">язык PHP</a></li>
<li><a href="http://about-programming.ru">языки программирования</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/%d0%ba%d0%b0%d0%ba-%d1%83%d0%b7%d0%bd%d0%b0%d1%82%d1%8c-ip-%d0%b8-mac-%d0%b0%d0%b4%d1%80%d0%b5%d1%81-%d1%81%d0%b2%d0%be%d0%b5%d0%b3%d0%be-%d0%ba%d0%be%d0%bc%d0%bf%d1%8c%d1%8e%d1%82%d0%b5%d1%80%d0%b0.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Особенности копирования текста страницы в CppWebBrowser на C++ Builder</title>
		<link>http://about-programming.ru/%d0%be%d1%81%d0%be%d0%b1%d0%b5%d0%bd%d0%bd%d0%be%d1%81%d1%82%d0%b8-%d0%ba%d0%be%d0%bf%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d1%82%d0%b5%d0%ba%d1%81%d1%82%d0%b0-%d1%81%d1%82%d1%80%d0%b0%d0b.html</link>
		<comments>http://about-programming.ru/%d0%be%d1%81%d0%be%d0%b1%d0%b5%d0%bd%d0%bd%d0%be%d1%81%d1%82%d0%b8-%d0%ba%d0%be%d0%bf%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d1%82%d0%b5%d0%ba%d1%81%d1%82%d0%b0-%d1%81%d1%82%d1%80%d0%b0%d0b.html#comments</comments>
		<pubDate>Sat, 02 Jan 2010 14:05:41 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[CppWebBrowser]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=586</guid>
		<description><![CDATA[В интернете выложено несколько похожих способов копирования текста (ну или html-текста, не суть) с компоненты CppWebBrowser. Я использовал следующий рабочий вариант копирования html-текста в Memo: IHTMLDocument2 *HTMLDocument = NULL; IPersistFile *PersistFile = NULL; LONG ilFramesCount = 0; AnsiString slTmpFileExtension = ".html"; // Falls eine Seite geladen: if(!Form1->CppWebBrowser1->Busy &#038;&#038; Form1->CppWebBrowser1->Document &#038;&#038; AnsiString(Form1->CppWebBrowser1->LocationURL) != "about:blank" &#038;&#038; SUCCEEDED(Form1->CppWebBrowser1->Document->QueryInterface(IID_IHTMLDocument2, [...]]]></description>
			<content:encoded><![CDATA[<p>В интернете выложено несколько похожих способов копирования текста (ну или html-текста, не суть) с компоненты <strong><a href="http://about-programming.ru/tag/cppwebbrowser">CppWebBrowser</a></strong>.<br />
Я использовал следующий рабочий вариант копирования html-текста в Memo:<span id="more-586"></span></p>
<p><code><br />
IHTMLDocument2 *HTMLDocument = NULL;<br />
IPersistFile *PersistFile = NULL;<br />
LONG ilFramesCount = 0;<br />
AnsiString slTmpFileExtension = ".html";<br />
// Falls eine Seite geladen:<br />
if(!Form1-><strong>CppWebBrowser</strong>1->Busy &#038;&#038; Form1-><strong>CppWebBrowser</strong>1->Document &#038;&#038;<br />
AnsiString(Form1-><strong>CppWebBrowser</strong>1->LocationURL) != "about:blank" &#038;&#038;<br />
SUCCEEDED(Form1-><strong>CppWebBrowser</strong>1->Document->QueryInterface(IID_IHTMLDocument2, (LPVOID*)&#038;HTMLDocument)))<br />
{<br />
// HTML-Code des Hauptdokuments speichern:<br />
       if(SUCCEEDED(HTMLDocument->QueryInterface(IID_IPersistFile,(LPVOID*)&#038;PersistFile)))<br />
       {<br />
               // HTML-Code des Hauptdokuments speichern:<br />
               PersistFile->Save(WideString(String(ExtractFilePath(ParamStr(0))+"0"+slTmpFileExtension)), false);<br />
               PersistFile->Release();<br />
               // ggf. auch Frames-Code extrahieren:<br />
               IHTMLFramesCollection2 *pFrames = NULL;<br />
               if(SUCCEEDED(HTMLDocument->get_frames(&#038;pFrames)))<br />
               {<br />
               // Anzahl der Frames bestimmen:<br />
               pFrames->get_length(&#038;ilFramesCount);<br />
               if(ilFramesCount < 2) ilFramesCount= 0;<br />
               VARIANT vFrame;<br />
               VARIANT ret;<br />
               vFrame.vt = VT_UINT;<br />
               // f?r jedes Frame:<br />
               for(LONG ilFrameIndex = 0; ilFrameIndex < ilFramesCount; ilFrameIndex++)<br />
               {<br />
                       vFrame.lVal = ilFrameIndex;<br />
                       if(SUCCEEDED(pFrames->item(&#038;vFrame, &#038;ret)))<br />
                       {<br />
                               // Zeiger auf IHTMLWindow2 des Frames besorgen:<br />
                               IHTMLWindow2 *pWindow = NULL;<br />
                               if(SUCCEEDED(ret.pdispVal->QueryInterface(IID_IHTMLWindow2,<br />
                               (LPVOID*)&#038;pWindow)))<br />
                               {<br />
                                       // Zeiger auf IHTMLDocument2 des Frames besorgen:<br />
                                       IHTMLDocument2 *pDoc = NULL;<br />
                                       if(SUCCEEDED(pWindow->get_document(&#038;pDoc)))<br />
                                       {<br />
                                               // Frame in der Datei "Framenummer.html" speichern:<br />
                                               IPersistFile *PersistFile = NULL;<br />
                                               if(SUCCEEDED(pDoc->QueryInterface(IID_IPersistFile,<br />
                                               (LPVOID*)&#038;PersistFile)))<br />
                                               {<br />
                                                       PersistFile->Save(WideString(String(ExtractFilePath(ParamStr(0))+<br />
                                                       IntToStr(ilFrameIndex+1) + slTmpFileExtension)), false);<br />
                                                       PersistFile->Release();<br />
                                               }<br />
                                               pDoc->Release();<br />
                                       }<br />
                                       pWindow->Release();<br />
                               }<br />
                       }<br />
               }<br />
               pFrames->Release();<br />
       }<br />
}<br />
HTMLDocument->Release();<br />
TStringList* pFileStrings = new TStringList;<br />
if(pFileStrings)<br />
{<br />
// Die gepufferten Dateien mit dem HTML-Code der<br />
// Seite in die RichEdit einlesen und die Dateien l?schen:<br />
       if(FileExists(ExtractFilePath(ParamStr(0))+"0"+slTmpFileExtension))<br />
               {<br />
                       Form1->Memo1->Lines->LoadFromFile(ExtractFilePath(<br />
                       ParamStr(0))+"0"+slTmpFileExtension);<br />
                       DeleteFile(ExtractFilePath(ParamStr(0))+"0"+slTmpFileExtension);<br />
               }<br />
       if(ilFramesCount > 0)<br />
               {<br />
               for(LONG ilFrameIndex = 0; ilFrameIndex < ilFramesCount; ilFrameIndex++)<br />
                       {<br />
                               if(FileExists(ExtractFilePath(ParamStr(0))+IntToStr(<br />
                               ilFrameIndex+1) + slTmpFileExtension))<br />
                               {<br />
                                       pFileStrings->LoadFromFile(ExtractFilePath(ParamStr(0))+<br />
                                       IntToStr(ilFrameIndex+1) + slTmpFileExtension);<br />
                                       Form1->Memo1->Lines->Add("\n- - - Frame " +<br />
                                       IntToStr(ilFrameIndex+1) + " - - -");<br />
                                       Form1->Memo1->Lines->Add(pFileStrings->Text);<br />
                                       DeleteFile(ExtractFilePath(ParamStr(0))+IntToStr(<br />
                                       ilFrameIndex+1) + slTmpFileExtension);<br />
                               }<br />
                       }<br />
               }<br />
       delete pFileStrings;<br />
       }<br />
}<br />
else Form1->Memo1->Lines->Clear();<br />
</code></p>
<p>Проблема в следующем&#8230; Текст извлекаю из известного сайта vkontakte.ru. Предположим, захожу в поиск людей.. мне выводится несколько страниц, к примеру по 10 человек. Копирую текст для первых 10 &#8212; всё Ок. А вот если хочу скопировать текст для следущих 10 найденных, то копируется текст снова для первых 10 В код копирования страницы не вникал ибо не особо в этих приёмах разбираюсь, а если начну разбираться то уйдёт на это много времени&#8230;<br />
Вопрос в следующем: можно как-нибудь подправить этот код или может, кто в работе с html страницами хоро?о разбирается, предложит свой вариант для ре?ения проблемы?</p>
<hr />
<p><code>AnsiString GetAllTextFromWebPage(TCppWebBrowser *wb)<br />
{<br />
        AnsiString s = wb->OleObject.OlePropertyGet("Document").OlePropertyGet("Body").OlePropertyGet("InnerText");<br />
        return s;<br />
}</code><br />
Сам на днях перерыл много инфы, ни чего толком не на?ел, но при?ел к такому изяществу, через COM-объект получае?ь весь текст на странице<br />
Если нужен HTML код странице, меняе?ь только значение переменной, кажется так, пробуй:<br />
<code>AnsiString GetHTMLTextFromWebPage(TCppWebBrowser *wb)<br />
{<br />
        AnsiString s = wb->OleObject.OlePropertyGet("Document").OlePropertyGet("Body").OlePropertyGet("InnerHtml");<br />
        return s;<br />
}</code></p>
<hr />
<p>Проблема в том, что в цикле браузер не успевает загрузить содержимое страницы и на этом этапе возникает о?ибка доступа. Все ре?иться если знать как дождаться определенного события = загрузки страницы, и только после этого запускать остальные фунциии цикла, стоит вопрос, как это сделать?</p>
<p>Проблема ре?ается  следущим образом, в теле цикла где происходит обработка страницы пи?ем сразу после того как браузер получает адрес страницы <a href="http://about-programming.ru/tag/cppwebbrowser">CppWebBrowser</a>->Navigate2(URL)</p>
<p><code>while (CppWebBrowser->ReadyState != 4)<br />
{<br />
  Application->ProcessMessages();;<br />
}</code></p>
<blockquote><p><strong>Похожая статья:</strong><br />
<a href="http://about-programming.ru/ccc/586.html">Особенности копирования текста страницы в CppWebBrowser на C++ Builder</a></p></blockquote>
<p>Мой блог о программировании находят по следующим фразам</p>
<ul>
<li><a href="http://about-programming.ru">Все о программировании</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/php.html">язык PHP</a></li>
<li><a href="http://about-programming.ru/category/php.html">php программирование</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/assembler.html">язык программирования assembler</a></li>
<li><a href="http://about-programming.ru/category/delphipascal.html">программирование на pascal</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/%d0%be%d1%81%d0%be%d0%b1%d0%b5%d0%bd%d0%bd%d0%be%d1%81%d1%82%d0%b8-%d0%ba%d0%be%d0%bf%d0%b8%d1%80%d0%be%d0%b2%d0%b0%d0%bd%d0%b8%d1%8f-%d1%82%d0%b5%d0%ba%d1%81%d1%82%d0%b0-%d1%81%d1%82%d1%80%d0%b0%d0b.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title></title>
		<link>http://about-programming.ru/%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d0%b1%d1%80%d0%b0%d1%83%d0%b7%d0%b5%d1%80-%d0%bd%d0%b0-%d1%81builder.html</link>
		<comments>http://about-programming.ru/%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d0%b1%d1%80%d0%b0%d1%83%d0%b7%d0%b5%d1%80-%d0%bd%d0%b0-%d1%81builder.html#comments</comments>
		<pubDate>Sat, 02 Jan 2010 13:56:28 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[CppWebBrowser]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=582</guid>
		<description><![CDATA[Продолжаю тему клонирования программ darkamster&#8217;a на Delphi в С++Builder. В этой статье я покажу, как с помощью стандартных компонентов, можно создать свой браузер. Браузер будет на движке &#8216;всеми-любимого&#8217; InternetExplorer. На? зверь сможет ходить по URL, смотреть Html странички, ходить вперед и назад, конечно, перезагружать странички и останавливать загрузку. Начнем новый проект. Советую сразу определиться с [...]]]></description>
			<content:encoded><![CDATA[<p>Продолжаю тему клонирования программ darkamster&#8217;a на Delphi в <strong>С++Builder</strong>. В этой статье я покажу, как с помощью стандартных компонентов, можно создать свой браузер. Браузер будет на движке &#8216;всеми-любимого&#8217; InternetExplorer. На? зверь сможет ходить по URL, смотреть Html странички, ходить вперед и назад, конечно, перезагружать странички и останавливать загрузку.<span id="more-582"></span><br />
Начнем новый проект. Советую сразу определиться с дизайном программы, не стоит далеко отходить от принятых стандартов, т.е кнопки навигации вверху, чуть ниже поле для ввода адреса URL, под ними будет располагаться просмотровщик страниц (компонент <strong><a href="http://about-programming.ru/tag/cppwebbrowser">CppWebBrowser</a></strong>).</p>
<p><img class="aligncenter" title="Пи?ем браузер" src="http://i-faq.ru/uploads/posts/2007-09/1190994432_builder1.jpg" alt="" width="231" height="144" />Я вместо button использовал компонент panel (это моя задумка &#8212; во время наведения курсора панелька будет подсвечена, как это реализовать я напи?у в самом конце). Под навигацией у меня располагается Edit для ввода адреса, под ним компонент <strong><a href="http://about-programming.ru/tag/cppwebbrowser">CppWebBrowser</a></strong>, так же нам понадобиться компонент OpenDialod &#8212; для просмотра страничек с жесткого диска. ?так, впервую очередь мы распи?ем событие, совер?аемое при нажатии enter в edit (с учетом того, что пользователь указал адрес сайта, событие называется &#8212; OnKeyPress). Вот код:</p>
<p><code>if (Key == VK_RETURN){ // нажат ЕНТЕР<br />
wchar_t URL[100];<br />
Edit1-&gt;Text.WideChar(URL,100); //Edit1 принял адрес сайта<br />
<strong>CppWebBrowser</strong>-&gt;Navigate(URL,0,NULL,NULL,NULL); //Адрес направлен на <strong>cppwebbrowser</strong>, по?ла загрузка<br />
}</code></p>
<p>Далее напи?ем код для кнопки открыть:</p>
<p><code>OpenDialog1-&gt;Execute(); //Открываем окно выбора файлов<br />
wchar_t URL[100];<br />
Edit1-&gt;Text=(OpenDialog1-&gt;FileName); //Присваемаем Edit название выбраного файла<br />
Edit1-&gt;Text.WideChar(URL,100);<br />
<strong>CppWebBrowser</strong>-&gt;Navigate(URL,0,NULL,NULL,NULL);</code></p>
<p>Кнопка назад:</p>
<p><code><strong>CppWebBrowser</strong>-&gt;GoBack();</code></p>
<p>Кнопка вперед:</p>
<p><code><strong>CppWebBrowser</strong>-&gt;GoForward();</code></p>
<p>Кнопка стоп:</p>
<p><code><strong>[block]2[/block]</strong>-&gt;Stop();</code></p>
<p>Кнопка Обновить:</p>
<p><code><strong>[block]3[/block]</strong>-&gt;Refresh();</code></p>
<p>Все готово =) Браузер будет спокойно бороздить просторы инета, под ва?им чутким контролем. Теперь я распи?у то, как менять цвет панелек при наведении. ?так, для начала обговорим, что стандартным цветом на?их panel будет &#8212; clBtnFace. Теперь ставим на OnMouseMove, следующий код:</p>
<p><code>Panel1-&gt;Color=clSkyBlue; //я выбрал цвет - небесно синий</code></p>
<p>В результате чего, при наведии панель поменяет цвет, теперь заставим вернуть ее преждний цвет (если пользователь убрал мы?ь). Сперва, мы должны выбрать событие OnMouseMove для Form1 и теперь пи?ем код:</p>
<p><code>Panel1-&gt;Color=clBtnFace; //результат панель приняла стандартный цвет</code></p>
<p>Мой блог о программировании находят по следующим фразам</p>
<ul>
<li><a href="http://about-programming.ru">Все о программировании</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/php.html">язык PHP</a></li>
<li><a href="http://about-programming.ru/category/php.html">php программирование</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/assembler.html">язык программирования assembler</a></li>
<li><a href="http://about-programming.ru/category/delphipascal.html">программирование на pascal</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/%d0%bf%d0%b8%d1%88%d0%b5%d0%bc-%d0%b1%d1%80%d0%b0%d1%83%d0%b7%d0%b5%d1%80-%d0%bd%d0%b0-%d1%81builder.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Ввод/вывод с помощью функции CreateFile</title>
		<link>http://about-programming.ru/%d0%b2%d0%b2%d0%be%d0%b4%d0%b2%d1%8b%d0%b2%d0%be%d0%b4-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-createfile.html</link>
		<comments>http://about-programming.ru/%d0%b2%d0%b2%d0%be%d0%b4%d0%b2%d1%8b%d0%b2%d0%be%d0%b4-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-createfile.html#comments</comments>
		<pubDate>Tue, 29 Dec 2009 23:50:21 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[Delphi/Pascal]]></category>
		<category><![CDATA[CreateFile]]></category>
		<category><![CDATA[Win32]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=565</guid>
		<description><![CDATA[В Win32 файл открывается при помощи функции, имеющей обманчивое название: function CreateFile(IpFileName: PChar; dwDesiredAccess, dwShareMode: DWORD; IpSecurityAttributes: PSecurityAttributes; dwCreationDistribution, dwFlagsAndAttributes: DWORD; hTemplateFile: THandle): THandle Хоть ее название и начинается с create, но она позволяет не только создавать, но и открывать уже существующие файлы. Такое огромное количество параметров оправдано, т. к. createFile используется для открытия файлов [...]]]></description>
			<content:encoded><![CDATA[<p><span style="font-family: Verdana; font-size: small;"> В <a href="http://about-programming.ru/tag/win32">Win32</a> файл открывается при помощи функции, имеющей обманчивое название: </span></p>
<blockquote><p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> <strong>function</strong> <strong><a href="http://about-programming.ru/tag/createfile">CreateFile</a></strong>(IpFileName: PChar; dwDesiredAccess, </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">dwShareMode: DWORD;   IpSecurityAttributes: PSecurityAttributes;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> dwCreationDistribution, dwFlagsAndAttributes: DWORD; </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">hTemplateFile: THandle): THandle</span> </span></p></blockquote>
<p><span style="font-family: Verdana; font-size: small;"> Хоть ее название и начинается с<strong> <span style="font-family: Verdana; font-size: x-small;">create</span></strong>, но она позволяет не только создавать, но и открывать уже существующие файлы. </span></p>
<p><span style="font-family: Verdana; font-size: small;"> Такое огромное количество параметров оправдано, т. к. <span style="font-family: Verdana; font-size: x-small;"> createFile</span> используется для открытия файлов на диске, устройств, каналов, портов и вообще любых источников ввода/вывода.<span id="more-565"></span></span></p>
<p><span style="font-family: Verdana; font-size: small;"> Функция <strong><span style="font-family: Verdana; font-size: x-small;"> createFile</span></strong> возвращает дескриптор открытого объекта ввода/вывода. Если открытие невозможно из-за о?ибок, возвращается код <span style="font-family: Verdana; font-size: x-small;">INVALID_HANDLE_VALUE</span>, а рас?иренный код о?ибки можно узнать, вызвав функцию<strong> </strong><span style="font-family: Verdana; font-size: x-small;">GetLastError</span>. </span></p>
<p><span style="font-family: Verdana; font-size: small;"> Закрывается файл в <a href="http://about-programming.ru/tag/win32">Win32</a> функцией <strong><span style="font-family: Verdana; font-size: x-small;">closeHandie</span></strong> (не <strong><span style="font-family: Verdana; font-size: x-small;">closeFile</span></strong>, a <strong><span style="font-family: Verdana; font-size: x-small;">closeHandle</span></strong>! Правда, &#171;легко&#187; запомнить? Что поделать, так их назвали разработчики Win32). </span></p>
<p><span style="font-family: Verdana; font-size: small;"> Приведем из боль?ого разнообразия несколько приемов использования функции <strong><span style="font-family: Verdana; font-size: x-small;">CreateFile</span></strong>. Часто программисты хотят иметь возможность организовать посекторный доступ к физическим устройствам хранения — например к дискете. Сделать это не так уж сложно, но при этом методы для Windows 98 и Windows 2000 различаются. В Windows 2000 придется открывать устройство (&#8216;\\.\A:&#8217;), а в Windows 98 — специальный драйвер доступа (обозначается &#8216;\\.\vwin32&#8242;). ? то и другое делается функцией <strong><span style="font-family: Verdana; font-size: x-small;">createFile</span></strong>.</span></p>
<p style="text-align: center;"><span style="font-family: Verdana; font-size: small;">Чтение    сектора с дискеты при помощи функции CreateFile</span></p>
<blockquote><p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> type</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> pDIOCRegs  = ^TDIOCRegs;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> TDIOCRegs = packed record</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> rEBX,rEDX,rECX,rEAX,rEDI, rESI, rFlags : DWORD;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> end;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> const VWIN32_DIOC_DOS_IOCTL = 1;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> VWIN32_DIOC_DOS_INT13  =  4;        //Прерывание 13</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> SectorSize = 512;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> function ReadSector(Head, Track, Sector: Integer; buffer : pointer; </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">Floppy: char):Boolean; </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> var hDevice : THandle; </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> Regs : TDIOCRegs;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> DevName : string; nb : Integer; </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> begin</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> if WIN32PLATFORM &lt;&gt; VER_PLATFORM_WIN32_NT then</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> begin {win95/98} hDevice := CreateFile(&#8216;\\.\vwin32&#8242;, GENERIC_READ, 0, nil, 0,</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> FILE_FLAG_DELETE_ON_CLOSE, 0);</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> if (hDevice = INVALID_HANDLE_VALUE) then</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> begin</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> Result := FALSE;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> Exit; end;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> regs.rEDX := Head * $100 + Ord(Floppy in ['b', 'B']);</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> regs.rEAX := $201; // KOH onepam-iM read sector</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> regs.rEBX := DWORD(buffer); // buffer</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> regs.rECX := Track * $100 + Sector;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> regs.rFlags := $0;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> Result := DeviceloControl(hDevice,VWIN32_DIOC_DOS_INT13,</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> @regs, sizeof(regs),  @regs, sizeof(regs), nb, nil) </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> and ((regs.rFlags and $1)=0); CloseHandle(hDevice); </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> end {win95/98} </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> else</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> begin // Windows NT/2000 </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> DevName :=&#8217;\\.\A:&#8217;;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> if Floppy in ['b', 'B'] then DevName[5] := Floppy;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> hDevice := CreateFile(pChar(Devname), GENERIC_READ,     FILE_SHARE_READ </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> or FILE_SHARE_WRITE, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> if (hDevice = INVALID_HANDLE_VALUE) then </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> begin </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> Result := FALSE;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">Exit;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">end;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">SetFilePointer(hDevice, (Sector-1)*SectorSize, nil, FILE_BEGIN); // нумерация с 1</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"><span style="font-family: Verdana; font-size: x-small;"> Result := ReadFile(hDevice, buffer&#8217;;, SectorSize, nb, nil) and (nb=SectorSize);</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> CloseHandle(hDevice);</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> end; // Windows NT/2000 </span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">end;</span> </span></p></blockquote>
<p><span style="font-family: Verdana; font-size: small;"> Для чтения и записи данных в Win32 используются функции: </span></p>
<blockquote><p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> function ReadFile(hFile: THandle; var Buffer; nNumberOfBytesToRead: DWORD; var IpNumberOfBytesRead: DWORD; IpOverlapped: POverlapped): BOOL; function WriteFile(hFile: THandle; const Buffer; nNumberOfBytesToWrite: DWORD; var IpNumberOfBytesWritten: DWORD; IpOverlapped: POverlapped): BOOL;</span> </span></p></blockquote>
<p><span style="font-family: Verdana; font-size: small;"> Здесь все сходно с <span style="font-family: Verdana; font-size: x-small;">BlockRead</span> и <span style="font-family: Verdana; font-size: x-small;">Blockwrite: hFile</span> — это дескриптор файла, <span style="font-family: Verdana; font-size: x-small;"> Buffer</span> — адрес, по которому будут читаться (писаться) данные; третий параметр означает требуемое число читаемых (записываемых) байтов, а четвертый — фактически прочитанное (записанное). Последний параметр — <span style="font-family: Verdana; font-size: x-small;"> IpOverlapped</span> — обсудим чуть позже. </span></p>
<p><span style="font-family: Verdana; font-size: small;"> Функция <span style="font-family: Verdana; font-size: x-small;"> createFile</span> используется и для доступа к портам ввода/вывода. Часто программисты сталкиваются с задачей: как организовать обмен данными с различными нестандартными устройствами, подключенными к параллельному или последовательному порту? В Turbo Pascal для DOS был очень хоро?ий псевдомассив <span style="font-family: Verdana; font-size: x-small;"> Ports</span>: пи?е?ь <span style="font-family: Verdana; font-size: x-small;"> Port[x] := у;</span> и не знае?ь проблем. В Win32 прямой доступ к портам запрещен и приходится открывать их как файлы: </span></p>
<blockquote><p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;">&#8230;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> hCom := CreateFile(&#8216;COM2&#8242;, GENERIC_READ or GENERIC_WRITE,</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> 0, NIL, OPEN_EXISTING, FILE_FLAG__OVERLAPPED, 0) ;</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> if hCom = INVALID_HANDLE_VALUE then</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> begin</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> raise EAbort.CreateFmt(&#8216;О?ибка открытия порта: %d*,[GetLastError]);</span> </span></p>
<p><span style="font-family: Verdana; font-size: small;"> <span style="font-family: Verdana; font-size: x-small;"> end;</span> </span></p></blockquote>
<p><span style="font-family: Verdana; font-size: small;"> Самое  боль?ое  отличие  от  предыдущего  примера —  в  скромном  флаге <span style="font-family: Verdana; font-size: x-small;">FILE_FLAG_OVERLAPPED</span>.</span></p>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/%d0%b2%d0%b2%d0%be%d0%b4%d0%b2%d1%8b%d0%b2%d0%be%d0%b4-%d1%81-%d0%bf%d0%be%d0%bc%d0%be%d1%89%d1%8c%d1%8e-%d1%84%d1%83%d0%bd%d0%ba%d1%86%d0%b8%d0%b8-createfile.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title></title>
		<link>http://about-programming.ru/%d1%80%d0%b0%d1%81%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-8-%d1%84%d0%b5%d1%80%d0%b7%d0%b5%d0%b9-%d0%bd%d0%b0-%d1%88%d0%b0%d1%85%d0%bc%d0%b0%d1%82%d0%bd%d0%be%d0%b9-%d0%b4%d0%be%d1%81%d0%bad.html</link>
		<comments>http://about-programming.ru/%d1%80%d0%b0%d1%81%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-8-%d1%84%d0%b5%d1%80%d0%b7%d0%b5%d0%b9-%d0%bd%d0%b0-%d1%88%d0%b0%d1%85%d0%bc%d0%b0%d1%82%d0%bd%d0%be%d0%b9-%d0%b4%d0%be%d1%81%d0%bad.html#comments</comments>
		<pubDate>Tue, 29 Dec 2009 23:37:25 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>
		<category><![CDATA[8 ферзей]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=560</guid>
		<description><![CDATA[Пробовали ли вы когда-нибудь расставить 8 ферзей на ?ахматной доске так, чтобы ни один из них не находился под ударом? Зная, что ферзь бьет по вертикали, горизонтали и диагонали, довольно непросто подобрать такую позицию. Но не для С. Неболь?ая программа за считанные минуты выдаст вам около 90 таких позиций, например, вот такую: int col[8], up_free[15], [...]]]></description>
			<content:encoded><![CDATA[<p>Пробовали ли вы когда-нибудь расставить <a href="http://about-programming.ru/tag/8-%D1%84%D0%B5%D1%80%D0%B7%D0%B5%D0%B9">8 ферзей</a> на ?ахматной доске так, чтобы ни один из них не находился под ударом? Зная, что ферзь бьет по вертикали, горизонтали и диагонали, довольно непросто подобрать такую позицию. Но не для С.<span id="more-560"></span> Неболь?ая программа за считанные минуты выдаст вам около 90 таких позиций, например, вот такую:</p>
<p><img class="aligncenter" title="Расстановка 8 ферзей" src="http://www.codenet.ru/progr/alg/ferzi.gif" alt="" width="205" height="205" /></p>
<p><code><br />
int col[8], up_free[15], dn_free[15], coln[8] ;</code></p>
<p>main( )<br />
{<br />
int i ;</p>
<p>for ( i = 0 ; i &lt;= 7 ; i++ )<br />
col[i] = 1 ;<br />
for ( i = 0 ; i &lt;= 14 ; i++ )<br />
up_free[i] = dn_free[i] = 1 ;<br />
clrscr( ) ;<br />
addqueen( ) ;<br />
}</p>
<p>addqueen( )<br />
{<br />
int i, c, r ;<br />
static int comb, row = -1 ;</p>
<p>row++ ;</p>
<p>/* Проверяем колонки */<br />
for ( i = 0 ; i &lt;= 7 ; i++ )                 {                     /* если клетка не находится под ударом */                     if ( col[i] &amp;&amp; up_free[i+row] &amp;&amp; dn_free[row-i+7])         {             			  /* запоминаем, что в строке находится ферзь */ 	          coln[row] = i ; 	           /* маркируем колонку и диагональ */  	          col[i] = 0 ;              	          up_free[i+row] = 0 ;              	          dn_free[row-i+7] = 0 ; 	           /* если заполнены все строки */             	          if ( row &gt;= 7 )<br />
{<br />
comb++ ;<br />
printf ( &#171;\n\n\ncombination no. %d&#187;, comb ) ;<br />
for ( r = 0 ; r &lt;= 7 ; r++ )<br />
{<br />
printf ( &#171;\n&#187; ) ;<br />
for ( c = 0 ; c &lt;= 7 ; c++ )<br />
{<br />
if ( c == coln[r] )<br />
printf ( &#187; Q &#187; ) ;<br />
else<br />
printf ( &#187; . &#187; ) ;<br />
}<br />
}<br />
}<br />
else<br />
addqueen( ) ;</p>
<p>/* снимаем пометку с колонки и диагонали */<br />
col[ coln[row] ] = 1 ;<br />
up_free[ row + coln[row] ] = 1 ;<br />
dn_free[ row - coln[ row ] + 7 ] = 1 ;<br />
}<br />
}<br />
row&#8212; ; /* умень?аем счетчик строк, пробуем следующую комбинацию */<br />
}</p>
<p>Мой блог о программировании находят по следующим фразам</p>
<ul>
<li><a href="http://about-programming.ru">Все о программировании</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/php.html">язык PHP</a></li>
<li><a href="http://about-programming.ru/category/php.html">php программирование</a></li>
<li><a href="http://about-programming.ru/category/ccc.html">программирование C++</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/assembler.html">язык программирования assembler</a></li>
<li><a href="http://about-programming.ru/category/delphipascal.html">программирование на pascal</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/%d1%80%d0%b0%d1%81%d1%81%d1%82%d0%b0%d0%bd%d0%be%d0%b2%d0%ba%d0%b0-8-%d1%84%d0%b5%d1%80%d0%b7%d0%b5%d0%b9-%d0%bd%d0%b0-%d1%88%d0%b0%d1%85%d0%bc%d0%b0%d1%82%d0%bd%d0%be%d0%b9-%d0%b4%d0%be%d1%81%d0%bad.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Чтение/запись блоков данных на C# (C Sharp)</title>
		<link>http://about-programming.ru/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%8c-%d0%b1%d0%bb%d0%be%d0%ba%d0%be%d0%b2-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d0%bd%d0%b0-c-c-sharp.html</link>
		<comments>http://about-programming.ru/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%8c-%d0%b1%d0%bb%d0%be%d0%ba%d0%be%d0%b2-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d0%bd%d0%b0-c-c-sharp.html#comments</comments>
		<pubDate>Mon, 28 Dec 2009 19:01:01 +0000</pubDate>
		<dc:creator>evteev</dc:creator>
				<category><![CDATA[C/C++/C#]]></category>

		<guid isPermaLink="false">http://about-programming.ru/?p=491</guid>
		<description><![CDATA[Чтение/запись блоков данных на C# (C Sharp) В этой статье речь пойдет о чтении/записи данных в файл, буфер или в память при помощи трех классов, образованых от абстрактного класс System.IO.Stream. Мы рассмотрим классы FileStream, MemoryStream, BufferedStream. Классы, производные от Stream(поток), предназначенны для работы с двоичными данными и могут искать какую-то часть данных в потоке. Сам [...]]]></description>
			<content:encoded><![CDATA[<p><strong>Чтение/запись блоков данных на C# (C Sharp)</strong></p>
<div>
<div>
<div>
<p>В этой статье речь пойдет о <strong>чтении/записи данных</strong> в файл, буфер или в память при помощи трех классов, образованых от абстрактного класс System.IO.Stream. Мы рассмотрим классы FileStream, MemoryStream, BufferedStream.</p>
<p>Классы, производные от Stream(поток), предназначенны для работы с двоичными данными и могут искать какую-то часть данных в потоке. Сам по себе, базовый класс уже имеет некоторые методы и свойства, который унаследованы в следующих классах. Вот список и предназначение этих методов и свойств.<span id="more-491"></span></p>
<table border="1" cellspacing="0" cellpadding="0" width="89%" bgcolor="#000" bordercolor="#ffffff">
<tbody>
<tr>
<td width="16%"><strong>CanRead</strong></td>
<td width="84%">Определяет, будет ли данный поток поддерживать чтение</td>
</tr>
<tr>
<td><strong>CanSeek</strong></td>
<td>Определяет, будет ли данный поток поддерживать поиск</td>
</tr>
<tr>
<td><strong>CanWrite</strong></td>
<td>? соответственно, будет ли поток поддерживать запись</td>
</tr>
<tr>
<td><strong>Close()</strong></td>
<td>Закрывает текущий поток и освобождает ресурсы</td>
</tr>
<tr>
<td><strong>Flush()</strong></td>
<td>Записывает все данные из буфера в соответствующий источник данных. Освобождает буфер</td>
</tr>
<tr>
<td><strong>Length</strong></td>
<td>Возвращает длину потока в байтах</td>
</tr>
<tr>
<td><strong>Position</strong></td>
<td>Определяет указатель на позицию в потоке</td>
</tr>
<tr>
<td><strong>Read()</strong></td>
<td>Читает последовательность байт</td>
</tr>
<tr>
<td><strong>ReadByte()</strong></td>
<td>Читает один байт</td>
</tr>
<tr>
<td><strong>Seek()</strong></td>
<td>Устанавливает указатель на местонахождение в текущем потоке</td>
</tr>
<tr>
<td><strong>SetLendth()</strong></td>
<td>Устанавливает длину текущего потока</td>
</tr>
<tr>
<td><strong>Write()</strong></td>
<td>Записывает последовательность байт</td>
</tr>
<tr>
<td><strong>WriteByte()</strong></td>
<td>Записывает один байт</td>
</tr>
</tbody>
</table>
<p>Перейдем к первому классу, унаследовав?ему эти элементы<br />
Класс FileStream</p>
<p>Этот класс предназначен для работы с файлами(их создание, чтение, запись). Вот пример его использования:</p>
<p>FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read);</p>
<p>Здесь переменная filename указывает на имя файла, а остальные параметры указывают на ограничения и допустимые действия над ним. Рассмотрим их поподробнее.</p>
<p>Перечесление FileMode:</p>
<table border="1" cellspacing="0" cellpadding="0" width="548" bgcolor="#000" bordercolor="#ffffff">
<tbody>
<tr>
<td width="175" valign="TOP"><strong>FileMode.Append</strong></td>
<td width="373">Открыть файл(переданный первым параметром) и установить указатель на конец файла(то есть для дописываения в него данных. Можно использовать только с <strong>FileAccess.Write</strong>, иначе будет сгенерировано исключение <strong>System.ArgumentException</strong>. Если файл отсутствует, то он создается автоматически и открывается для записи.</td>
</tr>
<tr>
<td valign="TOP"><strong>FileMode.Create</strong></td>
<td>Создать новый файл. Если файл уже существует, то перезаписать его.</td>
</tr>
<tr>
<td valign="TOP"><strong>FileMode.CreateNew</strong></td>
<td>Отличается от предыдущего тем, что если файл уже существует, то будет сгенерировано исключение</td>
</tr>
<tr>
<td valign="TOP"><strong>FileMode.Open</strong></td>
<td>Открыть файл и установить указатель на начало. Если файл не существует, будет сгенерировано исключение <strong>System.IO.FileNotFoundException</strong></td>
</tr>
<tr>
<td valign="TOP"><strong>FileMode.OpenOrCreate</strong></td>
<td>Отличается от предыдущего тем, что при отсутствии файла, его создает.</td>
</tr>
<tr>
<td valign="TOP"><strong>FileMode.Truncate</strong></td>
<td>Открывает существующий файл и обрезает его длину до 0 байт. Попытка прочитать файл с указанием такого перечисления приведет к исключению</td>
</tr>
</tbody>
</table>
<p>Перечисление FileAccess:</p>
<table style="height: 68px;" border="1" cellspacing="0" cellpadding="0" width="548" bgcolor="#000" bordercolor="#ffffff">
<tbody>
<tr>
<td width="181"><strong>FileAccess.Read</strong></td>
<td width="323">Файл открывается исключительно для чтения</td>
</tr>
<tr>
<td><strong>FileAccess.Write</strong></td>
<td>Файл открывается исключительно для записи</td>
</tr>
<tr>
<td><strong>FileAccess.ReadWrite</strong></td>
<td>Это комбо-вариант двух предыдущих</td>
</tr>
</tbody>
</table>
<p>Есть также перечисление FileShare, но оно для нас сейчас не является столь важным. Оно нужно для синхронизации записи или чтения с другими потоками.</p>
<p>Вот код, демонстрирующий простую запись в файл и чтение из него в консоль</p>
<p>FileStream stream = new FileStream(&#171;test.dat&#187;, FileMode.OpenOrCreate, FileAccess.ReadWrite);<br />
for(int i = 0: i &lt; 256; i++)<br />
{<br />
myFStream.WriteByte((byte)i);<br />
}<br />
<span style="color: #999999;">// Переставляем внутренний указатель на начало</span><br />
myFStream.Position = 0;<br />
<span style="color: #999999;">// Считываем байты из файла *.dat</span><br />
for(int i = 0; i &lt; 256; i++)<br />
(<br />
Console.Write(myFStream.ReadByte());<br />
}<br />
myFStream.Close();</p>
<h3>Класс MemoryStream</h3>
<p>Этот класс не особо отличается от предыдущего, нами рассмотренного, за исключением того, что он работает(записывает и читает) не с файлом, а с оперативной памятью. Ниже перечисленны наиболее важные его члены:</p>
<table style="height: 124px;" border="1" cellspacing="0" cellpadding="0" width="540" bgcolor="#000" bordercolor="#ffffff">
<tbody>
<tr>
<td width="116" valign="TOP"><strong>Capacity</strong></td>
<td width="609">Это свойство позволяет получить или установить кол-во байтов выделенных под этот поток</td>
</tr>
<tr>
<td valign="TOP"><strong>GetBuffer()</strong></td>
<td>Возвращает массив байтов при помощи которых был создан поток</td>
</tr>
<tr>
<td valign="TOP"><strong>ToArray()</strong></td>
<td>Записывает все содержимое потока в массив байтов не зависимо от свойства Position</td>
</tr>
<tr>
<td valign="TOP"><strong>WriteTo()</strong></td>
<td>Записывает все содержимое объекта(MemoryStream) в другой обьект класса, производного от Stream(например в FileStream)</td>
</tr>
</tbody>
</table>
<p>Вот пример кода осуществляющего запись в файл из MemoryStream через FileStream:</p>
<p>FileStream dumpFile = new FIleStream(&#171;Dump.dat&#187;, FleMode.Create, FileAccess.ReadWrlte);<br />
myMemStream.WriteTo(dumpFile);</p>
<p>myMemStream есть объект класса MemoryStream.</p>
<h3>Класс BufferedStream</h3>
<p>? завер?ает на?у тройку класс BufferedStream. Этот класс нужен для организации временного хранилища данных, чтобы потом передать их в постоянное хранилище. Казалось бы, для чего это нужно, разве не проще просто записать некоторые данные через FileStream.Write()? Конечно можно, но если нам нужна производительность, то луч?е использовать буфер, так как при многократном вызове FileStream.Write() нам приходиться много раз обращаться к диску, что существенно замедляет работу нащей программы.<br />
Вот пример использования BufferedStream</p>
<p><span style="color: #999999;">// Создаем объект BufferedStream. подключенный к уже имеющемуся объекту FileStream</span><br />
BufferedStream rnyFileBuffer = new BufferedStream(dumpFile);<br />
<span style="color: #999999;">// Добавляем в BufferedStream несколько байтов</span><br />
<span style="color: #0000ff;"> byte</span>[] str = {127, 0&#215;77, 0&#215;4, 0&#215;0, 0&#215;0, 0&#215;16};<br />
myFileBuffer.Write(str, 0, str.Length);<br />
<span style="color: #999999;">// А теперь записываем все содержимое BufferedStream в файл</span><br />
myFlleBuffer.Close();</p>
<p>Ну вот впринципе и все что. Успехов вам в программировании.</p>
<p><strong>Автор:</strong> CODER</p>
</div>
</div>
</div>
<p>Мой блог о программировании находят по следующим фразам</p>
<ul>
<li><a href="http://about-programming.ru">Все о программировании</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/php.html">язык PHP</a></li>
<li><a href="http://about-programming.ru/category/php.html">php программирование</a></li>
<li><a href="http://about-programming.ru/category/ccc.html">программирование C++</a></li>
<li><a href="http://about-programming.ru">языки программирования скачать</a></li>
<li><a href="http://about-programming.ru/category/assembler.html">язык программирования assembler</a></li>
<li><a href="http://about-programming.ru/category/delphipascal.html">программирование на pascal</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://about-programming.ru/%d1%87%d1%82%d0%b5%d0%bd%d0%b8%d0%b5%d0%b7%d0%b0%d0%bf%d0%b8%d1%81%d1%8c-%d0%b1%d0%bb%d0%be%d0%ba%d0%be%d0%b2-%d0%b4%d0%b0%d0%bd%d0%bd%d1%8b%d1%85-%d0%bd%d0%b0-c-c-sharp.html/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

