Форум программистов
  (#1) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию C/C++ FAQ - 01.05.2003, 10:59

О чем этот FAQ ?
******************************
1. Как вывести русские символы в стандартном потоке вывода?
2. Как правильно сравнивать строки?
3. Как преобразовать в программе число в строку?
4. Как определить, в какой операционной системе работает программа?
5. Как из работающей программы определить каталог, в котором она находится?
6. Как сделать коллбэк, если функции принадлежат к разным классам?
7. Как синхронизировать файловый менеджер с событиями изменений открытых файлов?
8. Как сделать DLL с нормальными экспортами, как у системных DLL Windows?
9. Какие стандартные функции сортировки лучше использовать?
10. Как узнать путь к какой-либо системной папке, например, Автозагрузка?
11. Как из работающей программы запустить внешнюю программу?
12. Почему при записи в файл размер файла получается больше, чем размер буфера с данными?
13. Bjarne Stroustrup's C++ Style and Technique FAQ.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#2) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:00

Q: Как вывести русские символы в стандартном потоке вывода? У меня вместо русских символов выводятся каракули.

A: Правильно выводить русские символы нужно так:
<div class='codetop'>Код C++</div><div class='codemain'>char buf[256]; *// размер буфера зависит от размера исходной строки
::CharToOem( "Привет, Мир!n", buf );
cout << buf;[/code]
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#3) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:01

Q: Как правильно сравнивать строки? Я сравниваю одинаковые строки и оказывается, что они не равны. Вот исходник:
Код:
BOOL Test()
{
 * char classname[256];
 * char editclass[256];
 * strcpy(classname, "edit");
 * strcpy(editclass, "edit");
 * if (classname == editclass) return TRUE;
 * else return FALSE;
}
Почему?

A: Потому, что имена символьных массивов в C++ - это указатели.
Указатели, естественно, не равны друг другу. Правильным решением будет применение функции strcmp:
Код:
if (strcmp(classname, editclass) == 0) return TRUE; *// строки совпали
else return FALSE; *// не совпали
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#4) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:02

Q: Как преобразовать в программе число в строку, с тем чтобы вывести его в какой-нибудь EditBox именно в виде строки?

A: Преобразовать число в строку можно так:
Код:
CString * str;
DWORD * dwVariable = 0x277FEA14;
str.Format("%x", dwVariable);
Можно применить функции itoa(), sprintf(). Для полной информации по функциям itoa(), sprintf(), CString::Format() см. MSDN.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#5) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:03

Q: Как программа может сама определить, в какой операционной системе она работает?

A: Как всегда - GetVersion() или GetVersionEx(). Пример:
Код:
OSVERSIONINFO osvi;
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
::GetVersionEx(&osvi);

BOOL bIsWindows98orLater =
 * * (osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) &&
 * * ( (osvi.dwMajorVersion > 4) ||
 * * ( (osvi.dwMajorVersion == 4) && (osvi.dwMinorVersion > 0) ) );
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#6) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:04

Q: Как програмно, из работающей программы определить каталог, в котором она находится? Это для того, чтобы потом запустить из этого каталога другую программу.

A: Нет ничего проще. Имя текущего каталога программно можно получить так:
Код:
TCHAR buffer[MAX_PATH + 1];
GetCurrentDirectory(MAX_PATH, buffer);
// в buffer получено имя каталога
Однако если программа при своей работе изменит текущий каталог, то функция вернет имя нового текущего каталога, а не того, из которого был запущен exe-файл программы. Поэтому получить имя каталога программы лучше всего как можно раньше после ее старта.

Второй вариант:
использовать функцию API GetModuleFileName:<div class='codetop'>Код C++</div><div class='codemain'>****TCHAR szPath[MAX_PATH + 1];
****ZeroMemory(szPath, sizeof(szPath));
****::GetModuleFileName(NULL, szPath, MAX_PATH));[/code]
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#7) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:05

Q: Как сделать коллбэк, если функции принадлежат к разным классам?

A: Вызывать функцию надо примерно так:
Код:
#include <iostream>
int f(int i)
{
 * std::cout << "i = " << i << std::endl;
 * return 0;
}
////////////////////////////
class A
{
public:
 * int fA(int i) { return f(i); }
};
////////////////////////////
class B
{
public:
 * typedef int (A::*PFA)(int);
 * // в конструкторе сохраняем указатель на функцию - для callback
 * B() { m_pFA = &A::fA; }

 * void fB()
 * {
 * * *// вызываем callback-функцию
 * * *(m_A.*m_pFA)(3);
 * }
private:
 * A m_A; // объект класса А
 * PFA m_pFA; // указатель на метод из класса А
};

typedef int (*PF)(int);

int main(int argc, char** argv)
{
 * // два способа сделать одно и то же:
 * int (*pf1)(int) = f; // здесь явно определяем указатель на функцию
 * PF pf2 = f; * * * * // а здесь через созданный тип указателя на функцию

 * pf1(1);
 * pf2(2);

 * B b;
 * // эмулируем callback-вызов
 * b.fB();

 * return 0;
}
И еще один небольшой комментарий.
Обратите внимание, что сохраненный указатель на член-функцию может быть применимым только к конкретному объекту (и это вполне логично!). Дело в том, что тот же Страуструп в п.15.5. объясняет причину этого: указатель на член-функцию больше соответствует некоторому смещению (относительно объекта), чем на самом деле указателю. Таким образом, объект (т.н. база) + смещение = нужная член-функция объекта. (Только не думайте, что это на самом деле смещение - в отличие от виртуальной функции! - что, голову совсем запутал?)
И вообще:
а) указатели на виртуальные члены-функции можно передавать между различными объектами (т.к. размещение такой функции по отношению к объекту регулируется положением в vtbl и не зависит от расположения объекта в памяти);
б) указатели на обыкновенные член-функции НЕЛЬЗЯ передавать между разными объектами.

См. также обсуждение в Форуме.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#8) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:06

Q: Как синхронизировать файловый менеджер с событиями изменений открытых файлов? В чем секрет?

A: Для этого используется функция FindFirstChangeNotification(), единственное "но" - функция оповещает об изменениях в директории, а не в конкретном файле, поэтому необходимо самому определить изменения. Можно делать это по размеру файла, а можно - считать для файла контрольную сумму CRC32. Подойдут и другие методы контроля за изменением содержимого файла.

См. также обсуждение в Форуме.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#9) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:06

Q: Как сделать DLL с нормальными экспортами, как у системных DLL Windows? Если пишу extern "C" __declspec(dllexport) int __stdcall func(int), получается (я надеюсь) stdcall, но имена _func@4; а хочется func.

A: Джеффри Рихтер пишет по этому поводу:
"Дело в том, что компилятор Microsoft С, экспортируя С-функцию, искажает eе имя, даже если Вы вообще не пользуетесь С++. Это происходит, только когда Ваша функция экспортируется по соглашению __stdcall. (Увы, это самое популярное соглашение.) Тогда компилятор Microsoft искажает имя С-функции, впереди ставит знак подчеркивания, а к концу добавляет суффикс, состоящий из символа @ и числа байтов, передаваемых функции в качестве параметров.
Например, следующая функция экспортируется в таблицу экспорта DLL как _MyFunc@8:
Код:
__declspec(dllexport) LONG __stdcall MyFunc(int a, int b);
Чтобы средствами Microsoft собрать DLL, способную работать с инструментарием от другого поставщика, нужно указать компилятору Microsoft экспортировать имя функции без искажений."

Сделать это можно несколькими способами.

Первый — создать DEF-файл для Вашего проекта и включить в него раздел EXPORTS так:
Код:
EXPORTS MyFunc
Компоновщик от Microsoft, анализируя этот DEF-файл, увидит, что экспортировать надо обе функции: _MyFunc@8 и MyFunc. Поскольку их имена идентичны (не считая вышеописанных искажений), компоновщик на основе информации из DEF-файла экспортирует только функцию с именем MyFunc, а функцию _MуFunc@8 не экспортирует вообще.

Второй — надо добавить в Linker->Command line->Additional Options к опциям линкера дополнительные параметры. Например, Вы экспортируете две функции и хотите обойтись без искажения имен, в command line нужно добавить:
Код:
/export:Func1 /export:Func2
Этот способ имеет небольшое ограничение: сравнительно небольшое число экспортируемых функций. Представьте себе программиста, судорожно пытающегося найти опечатку в опциях линкера "/export" для хотя бы полусотни экспортируемых имен...

Третий способ — Вы можете в .CPP файле написать
Код:
#pragma comment(linker, "/export:Func1=_Func1@4")
и линкер экспортирует как недекорированное имя Func1, так и декорированное имя _Func1@4, причем оба они будут указывать на одну и ту же функцию.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#10) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:08

Q: Какие стандартные функции сортировки лучше использовать?

A: В C++ это std::sort, qsort().
Вот результаты тестов. Все результаты получены на двух машинах, приведенные цифры - число тиков таймера, вычисленное как среднее из результатов пяти прогонов. Сравнивалась скорость сортировки четырехбайтовых и восьмибайтовых целых чисел. Код поразрядной сортировки и QSort написан и откомпилирован Delphi 7, код std::sort и qsort откомпилирован Intel C++ 4.5.

На машине Celeron 300, 192 Мб ОЗУ, шина 66 МГц:
Код:
Число эл-тов * * * 100`000 * *1`000`000 * 10`000`000
Разрядность,байт * 4 * * 8 * * 4 * * 8 * * 4 * * * 8

std::sort * * * * 80 * 130 * *851 *1143 * 9584 * 16954
qsort() C++ * * *221 * 381 * 2613 *5147 *62049 *124529
Поразрядная * * * 55 * 178 * *674 *2141 * 9684 * 22143
QSort (Delphi) * 100 * 168 * 1178 *2113 *14380 * 25136
На машине Celeron 1000, 512 Мб ОЗУ, шина 133 МГц:
Код:
Число элементов * * *100`000 * 1`000`000 * 10`000`000
Разрядность, байт * * 4 * *8 * * 4 * *8 * * *4 * * 8

std::sort * * * * * *20 * 30 * 301 * 561 * 3835 * 7330
qsort() C++ * * * * *70 *140 * 911 *1843 *20369 *41049
Поразрядная * * * * *20 * 83 * 223 * 836 * 2354 * 8482
QSort (Delphi) * * * 30 * 53 * 396 * 773 * 5038 * 9884
Подробнее см. здесь.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#11) Старый
Специалист
 
Сообщений: 3,053
Регистрация: 27.06.2002
Адрес: Санкт-Петербург
Отправить сообщение для Влад с помощью ICQ
По умолчанию 01.05.2003, 11:09

Q: Как узнать путь к какой-либо системной папке, например, Автозагрузка ?

A: Используй функцию оболочки SHGetSpecialFolderLocation(), это официально документированный Microsoft способ.
Идентификаторы соответствующих системных папок см. в MSDN.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#12) Старый
Senior Member
 
Сообщений: 1,380
Регистрация: 11.06.2002
Адрес: Киев
Отправить сообщение для Olesya с помощью ICQ Отправить сообщение для Olesya с помощью AIM
По умолчанию 02.05.2003, 22:12

Q: Как запустить внешнюю програму из своей?
A: Существует несколько вариантов решения этого вопроса.
1. system
Пример:
Код:
system( "c:program filesmyappmyapp.exe" );
2. WinExec
Пример:
Код:
WinExec("C:Program FilesmyAppmyApp.exe", SW_SHOW);
3. ShellExecute, ShellExecuteEx
Пример:
Код:
ShellExecute(handle, NULL, path_to_folder, NULL, NULL, SW_SHOWNORMAL);
4. CreateProcess
Пример:
Код:
STARTUPINFO start_info;
ZeroMemory( & start_info , sizeof( start_info) );
start_info.cb = sizeof(start_info);
PROCESS_INFORMATION proc_info;
ZeroMemory( & proc_info , sizeof( proc_info ) );
if(!CreateProcess(NULL,
“notepad.exe”, 
NULL,
NULL,
FALSE;
0,
****NULL,
****NULL,
****&start_ino,
****&proc_info))
 * *{
 * *printf(“Creation process failed!n”);
 * *return -1;
 * *}

Подробное описание см. в MSDN
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#13) Старый
Senior Member
 
Сообщений: 1,380
Регистрация: 11.06.2002
Адрес: Киев
Отправить сообщение для Olesya с помощью ICQ Отправить сообщение для Olesya с помощью AIM
По умолчанию Re: C/C++ FAQ - 25.06.2003, 21:37

Q: При записи в файл один буфер размером 4 кБ, а размер файла получается почти 5 кБ. Где ошибка?

А: Неправильно открыт файл. Он открыт как текстовый, соответствено, данные будут писаться как текст. Так как маркером конца строки в ОСях Microsoft является код 0x0D 0x0A (CR-LF), перед каждым байтом 0x0A будет дописан еще 0x0D. Чтобы было все правильно, надо файл открывать как бинарный.

Пример неправильного кода:
Код:
FILE *file = fopen("file.ext", "w"); * // Ошибка!!!
long cwb = fwrite(pBuffer, BUFFER_SIZE, CountBuffers, file);
fclose(file);
В этом случае размер файла будет BUFFER_SIZE*CountBuffers + [количество 0x0А во всех записываемых буферах].

Теперь пишем правильно:
Код:
FILE *file = fopen("file.ext", "wb");
long cwb = fwrite(pBuffer, BUFFER_SIZE, CountBuffers, file);
fclose(file);
В этом случае размер файла будет BUFFER_SIZE*CountBuffers.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#14) Старый
Senior Member
 
Сообщений: 1,219
Регистрация: 07.06.2002
Адрес: Оттуда!
По умолчанию 25.04.2005, 17:25

/* Возможно, это тоже будет кому-нибудь интересно и, что самое главное, полезно: */
Bjarne Stroustrup's C++ Style and Technique FAQ

Смотрите также дополнительные ссылки на странице.
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
  (#15) Старый
Senior Member
 
Сообщений: 818
Регистрация: 08.08.2003
По умолчанию 26.02.2007, 16:56

Q: Как сделать коллбэк, если функции принадлежат к разным классам?

A2:
В объектно-ориентированном стиле лучше всего использовать абстрактный callback-интерфейс:
<div class='codetop'>Код C++</div><div class='codemain'>class ICallback //abstract
{
public:
****virtual void notify() = 0;

protected:
****~ICallback() {}
};[/code]
Класс, который реализует вызов callback-функции, хранит у себя не указатель на функцию, как это обычно делается, а указатель на интерфейс ICallback:
<div class='codetop'>Код C++</div><div class='codemain'>class A
{
public:
****void set_callback( ICallback* _object ) { _remote_object = _object; }
****// ...
****void func();
****// ...
private:
****ICallback* _remote_object;
};

void A::func()
{
****// ...
****if ( _remote_object != NULL )
********_remote_object->notify();
}[/code]
Класс, нуждающийся в уведомлении от класса A, наследуется от ICallback и реализует метод notify():
<div class='codetop'>Код C++</div><div class='codemain'>class B : public ICallback
{
public:
****B( A& a ) { a.set_callback( this ); }
private:
****virtual void notify();
****// ...
};

void B::notify()
{
****// Реагируем на сообщение от класса A.
}[/code]

Преимущество такого подхода заключается в независимости интерфейса класса A от класса B. Он уже не нуждается в ссылке на класс B в callback-указателе, т.е. реализовать callback можно также в любом другом классе. Кроме того можно использовать интерфейсы с несколькими callback-функциями, а также можно добавить в callback-интерфейс указатель на свой класс для организации списка вызова.
Например:
<div class='codetop'>Код C++</div><div class='codemain'>class ICallbackInsertRemove //abstract
{
public:
****virtual void inserted( unsigned disk_number ) = 0;
****virtual void removed( unsigned disk_number ) = 0;

****ICallbackInsertRemove* next;

protected:
****ICallbackInsertRemove() : next( NULL ) {}
****~ICallbackInsertRemove() {}
};[/code]
Организация вызова примерно следующая:
<div class='codetop'>Код C++</div><div class='codemain'>void A::func()
{
****// ...
****for ( ICallbackInsertRemove* ro = _remote_object; ro != NULL; ro = ro->next )
********ro->inserted( disk ); // или, например, ro->removed( disk )
}[/code] Ну и, разумеется, для списка нужно доработать функцию set_callback() и, возможно, добавить функцию remove_callback().
Digg this Post!Bookmark Post in Technorati
Ответить с цитированием
Ответ

Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Trackbacks are Вкл.
Pingbacks are Вкл.
Refbacks are Вкл.




Powered by vBulletin® Version 3.8.5
Copyright ©2000 - 2010, Jelsoft Enterprises Ltd.
SEO by vBSEO 3.5.0 RC2