Начинаю вести блог про эффективное обучение: http://miracleteaching.blogspot.ru/
воскресенье, 15 декабря 2013 г.
вторник, 16 апреля 2013 г.
Как определить, есть ли файл на диске (Windows)
Для этого надо сравнить результат функции GetFileAttributes с -1:
GetFileAttributes(path) != DWORD(-1);
У функции GetFileAttributes есть две версии: для однобайтных символов (GetFileAttributesA) и для Unicode (GetFileAttributesW).
GetFileAttributes(path) != DWORD(-1);
У функции GetFileAttributes есть две версии: для однобайтных символов (GetFileAttributesA) и для Unicode (GetFileAttributesW).
Приведение типов в C++
Немного о приведении типов.
в С++ есть несколько вариантов приведения типов:
в С++ есть несколько вариантов приведения типов:
- const_cast,
- dynamic_cast,
- static_cast,
- reinterpret_cast,
- C-style cast.
const_cast используется для того, чтобы снять константность с объекта.
dynamic_cast используется для приведения типов в иерархии наследования.
static_cast используется для приведения одного типа к другому. При этом для встроенных типов используются встроенные правила приведения типов, а для остальных - правила, определенные программистом.
reinterpret_cast используется для низкоуровневого преобразования указателей. Компилятор считает, что программист лучше знает, как трактовать данную область памяти и тихо подчиняется. Следует применять с большой осторожностью.
C-style cast лучше не использовать в C++, потому что его трудно обнаружить в коде.
Приведение в стиле C делает static_cast, если он не подходит, делает reinterpret_cast, после этого, если надо, делает const_cast. Единственный вариант, которому нет аналога в C++ - это приведение к void.
Что делать, если в Windows 7 не работает центр обновлений и выдает ошибку 0xc8000222
Такое бывает, например, когда вы восстановили систему с образа восстановления на другую конфигурацию компьютера. У меня такое было, когда у меня посыпался винчестер на ноутбуке, и я восстановил систему уже на новый винчестер другого размера.
Для исправления требуется сделать следующие шаги:
1. Нажмите кнопку Пуск, Выполнить, введите команду: CMD и нажмите Enter. Выполните следующую команду в открывшемся окне.
net stop WuAuServ
2. Переименуйте папку %windir%\SoftwareDistribution в %windir%\SDold.
4. Нажмите кнопку Пуск, Выполнить, введите команду: CMD и нажмите Enter. Выполните следующую команду в открывшемся окне.
net start WuAuServ
Для исправления требуется сделать следующие шаги:
1. Нажмите кнопку Пуск, Выполнить, введите команду: CMD и нажмите Enter. Выполните следующую команду в открывшемся окне.
net stop WuAuServ
2. Переименуйте папку %windir%\SoftwareDistribution в %windir%\SDold.
4. Нажмите кнопку Пуск, Выполнить, введите команду: CMD и нажмите Enter. Выполните следующую команду в открывшемся окне.
net start WuAuServ
Специализация метода шаблонного класса
Сегодня рассмотрим специализацию шаблонов.
Создадим класс шаблонный A.
#include <string>
#include <iostream>
template <class T>
class A
{
private:
std::string f;
public:
void method();
};
template<class T>
void A<T>::method()
{
f = "some type";
std::cout << f << std::endl;
}
Теперь создадим специализацию для int:
template<>
class A<int>
{
private:
std::string f;
public:
void method();
};
Если мы омределим method следующим образом:
template <>
void A<int>::method()
{
f = "int";
std::cout << f << std::endl;
},
то получим ошибку о том, что метод нельзя спицифицировать дважды. В Visual Studio это ошибка №C2910. MSDN говорит, что требуется убрать template <> . Однако в полученном коде:
void A<int>::method()
{
f = "int";
std::cout << f << std::endl;
}
возникает ошибка линковки - функция-член method определена дважды в объектном файле.
Работающий вариант:
inline void A<int>::method()
{
f = "int";
std::cout << f << std::endl;
}
Создадим класс шаблонный A.
#include <string>
#include <iostream>
template <class T>
class A
{
private:
std::string f;
public:
void method();
};
template<class T>
void A<T>::method()
{
f = "some type";
std::cout << f << std::endl;
}
Теперь создадим специализацию для int:
template<>
class A<int>
{
private:
std::string f;
public:
void method();
};
Если мы омределим method следующим образом:
template <>
void A<int>::method()
{
f = "int";
std::cout << f << std::endl;
},
то получим ошибку о том, что метод нельзя спицифицировать дважды. В Visual Studio это ошибка №C2910. MSDN говорит, что требуется убрать template <> . Однако в полученном коде:
void A<int>::method()
{
f = "int";
std::cout << f << std::endl;
}
возникает ошибка линковки - функция-член method определена дважды в объектном файле.
Работающий вариант:
inline void A<int>::method()
{
f = "int";
std::cout << f << std::endl;
}
среда, 10 апреля 2013 г.
Shared library
Сегодня будем писать кросс-платформенную динамическую библиотеку (DLL).
Заведем заголовочный файл, в котором будут макросы для экспортирования функций в библиотеку в зависимости от платформы.
Файл export.h:
#ifndef _EXPORT_H
#define _EXPORT_H
#if defined (_MSC_VER)
#ifdef __cplusplus
#define LIB_EXPORT extern "C" __declspec(dllexport)
#else
#define LIB_EXPORT __declspec(dllexport)
#endif
#elif defined (__GNUC__)
#ifdef __cplusplus
#define LIB_EXPORT extern "C" __attribute__((visibility("default")))
#else
#define LIB_EXPORT __attribute__((visibility("default")))
#endif
#else
#warning Unknown dynamic link semantics
#ifdef __cplusplus
#define LIB_EXPORT extern "C"
#else
#define LIB_EXPORT
#endif
#endif
#endif
Теперь создадим саму библиотеку. Покажем, как делать экспорт функций и классов.
Файл export_functions.h:
#ifndef EXPORT_FUNCTIONS_H
#define EXPORT_FUNCTIONS_H
#include "export.h"
LIB_EXPORT int export_function(int x);
class EClass
{
public:
virtual void func() =0;
};
class EClassImpl : public EClass
{
public:
virtual void func();
};
LIB_EXPORT EClass *GetEClass();
LIB_EXPORT void DeleteEClass(EClass *a);
#endif
Для сборки в Visual Studio под Windows требуется создать проект типа Win32 Console application и указать, что это DLL.
Теперь создадим пользователя этой библиотеки. Первый вариант: У нас есть заголовочный файл и мы будем линковаться с ней при сборке.
Файл StaticUser.cpp:
#include <iostream>
#include "../SharedLibrary/export_functions.h"
int main(int argc, char **argv)
{
export_function(5);
EClass *a = GetEClass();
a->func();
DeleteEClass(a);
return 0;
}
Для сборки в Visual Studio под Windows в зависимостях проект (Project dependencies) требуется поставить проект SharedLibrary.
Второй вариант: У нас нет заголовочного файла, и мы будем загружать библиотеку самостоятельно.
В Windows загрузка DLL осуществляется при помощи функции LoadLibrary. Если загрузка DLL произошла удачно, возвращается переменная типа HINSTANCE (В VisualStudio этот тип определен как void *). В противном случае возвращается 0. Чтобы понять, какая произошла ошибка, вызываем функцию GetLastError. Коды ошибок в Windows можно посмотреть тут.
Пользователь библиотеки будет состоять из одного файла LibraryUser.cpp:
#include <iostream>
#include <Windows.h>
using namespace std;
typedef int (*export_function_t) (int);
export_function_t export_function;
int main(int argc, char **argv)
{
DWORD err;
LPCSTR path = (LPCSTR)"SharedLibrary.dll";
if (GetFileAttributesA(path) == -1) //file does not exist.
{
cout << "Library not found ):" << endl;
}
HINSTANCE hDLL = LoadLibraryA(path);
if (hDLL)
{
cout << "Library loaded!" << endl;
export_function = reinterpret_cast<export_function_t> (GetProcAddress(hDLL, "export_function"));
if (!export_function)
{
cout << "Function not loaded ):" << endl;
return 1;
}
cout << "Function export_function loaded!" << endl;
int x = export_function(5);
cout << "Function returned " << x << endl;
}
else
{
err = GetLastError();
cout << "Error in load library: " << err << endl;
}
return 0;
}
Под Linux загрузка библиотеки осуществляется функцией dlopen.
Линуксовый пользователь библиотеки будет состоять из файла lu.cpp:
#include <iostream>
#include <dlfcn.h>
#include <link.h>
#include "../SharedLibrary/export_functions.h"
using namespace std;
int main(int argc, char ** argv)
{
void *handle = dlopen("/lib/libshared.so", RTLD_LAZY);
if (!handle)
{
cerr << "Couldn't load library ):" << endl;
return 1;
}
EClass * (*GetEClass)();
void * (DeleteEClass)(EClass *);
GetEClass = (EClass* (*)())dlsym(handle, "GetEClass");
EClass *a = (EClass *) GetEClass();
a->func();
return 0;
}
Заведем заголовочный файл, в котором будут макросы для экспортирования функций в библиотеку в зависимости от платформы.
Файл export.h:
#ifndef _EXPORT_H
#define _EXPORT_H
#if defined (_MSC_VER)
#ifdef __cplusplus
#define LIB_EXPORT extern "C" __declspec(dllexport)
#else
#define LIB_EXPORT __declspec(dllexport)
#endif
#elif defined (__GNUC__)
#ifdef __cplusplus
#define LIB_EXPORT extern "C" __attribute__((visibility("default")))
#else
#define LIB_EXPORT __attribute__((visibility("default")))
#endif
#else
#warning Unknown dynamic link semantics
#ifdef __cplusplus
#define LIB_EXPORT extern "C"
#else
#define LIB_EXPORT
#endif
#endif
#endif
Теперь создадим саму библиотеку. Покажем, как делать экспорт функций и классов.
Файл export_functions.h:
#ifndef EXPORT_FUNCTIONS_H
#define EXPORT_FUNCTIONS_H
#include "export.h"
LIB_EXPORT int export_function(int x);
class EClass
{
public:
virtual void func() =0;
};
class EClassImpl : public EClass
{
public:
virtual void func();
};
LIB_EXPORT EClass *GetEClass();
LIB_EXPORT void DeleteEClass(EClass *a);
#endif
Файл export_functions.cpp:
#include <iostream>
#include "export_functions.h"
using namespace std;
int export_function(int x)
{
cout << "DLL function! parameter: " << x << endl;
return x;
}
EClass *GetEClass()
{
return new EClassImpl;
}
void DeleteEClass(EClass *a)
{
delete a;
}
void EClassImpl::func()
{
cout << "Class function from DLL!" << endl;
}
Положим все эти файлы в папку SharedLibrary.
Для сборки под Linux при помощи GCC можно использовать следующий Makefile:
libshared:
g++ -fPIC -Wall -g -c export_functions.cpp
g++ -shared -Wl,-soname, -o libshared.so export_functions.o -lc
clean:
rm -f *.o libshared.so
Файл libshared.so требуется либо положить в стандартное место для библиотек, либо перед использованием изменять переменную LD_LIBRARY_PATH.
Теперь создадим пользователя этой библиотеки. Первый вариант: У нас есть заголовочный файл и мы будем линковаться с ней при сборке.
Файл StaticUser.cpp:
#include <iostream>
#include "../SharedLibrary/export_functions.h"
int main(int argc, char **argv)
{
export_function(5);
EClass *a = GetEClass();
a->func();
DeleteEClass(a);
return 0;
}
Makefile для сборки под Linux:
StaticUser:
g++ -Wall -g -c StaticUser.cpp
g++ -g -o StaticUser StaticUser.o -L../SharedLibrary -lshared
Для сборки в Visual Studio под Windows в зависимостях проект (Project dependencies) требуется поставить проект SharedLibrary.
Второй вариант: У нас нет заголовочного файла, и мы будем загружать библиотеку самостоятельно.
В Windows загрузка DLL осуществляется при помощи функции LoadLibrary. Если загрузка DLL произошла удачно, возвращается переменная типа HINSTANCE (В VisualStudio этот тип определен как void *). В противном случае возвращается 0. Чтобы понять, какая произошла ошибка, вызываем функцию GetLastError. Коды ошибок в Windows можно посмотреть тут.
Пользователь библиотеки будет состоять из одного файла LibraryUser.cpp:
#include <iostream>
#include <Windows.h>
using namespace std;
typedef int (*export_function_t) (int);
export_function_t export_function;
int main(int argc, char **argv)
{
DWORD err;
LPCSTR path = (LPCSTR)"SharedLibrary.dll";
if (GetFileAttributesA(path) == -1) //file does not exist.
{
cout << "Library not found ):" << endl;
}
HINSTANCE hDLL = LoadLibraryA(path);
if (hDLL)
{
cout << "Library loaded!" << endl;
export_function = reinterpret_cast<export_function_t> (GetProcAddress(hDLL, "export_function"));
if (!export_function)
{
cout << "Function not loaded ):" << endl;
return 1;
}
cout << "Function export_function loaded!" << endl;
int x = export_function(5);
cout << "Function returned " << x << endl;
}
else
{
err = GetLastError();
cout << "Error in load library: " << err << endl;
}
return 0;
}
Под Linux загрузка библиотеки осуществляется функцией dlopen.
Линуксовый пользователь библиотеки будет состоять из файла lu.cpp:
#include <iostream>
#include <dlfcn.h>
#include <link.h>
#include "../SharedLibrary/export_functions.h"
using namespace std;
int main(int argc, char ** argv)
{
void *handle = dlopen("/lib/libshared.so", RTLD_LAZY);
if (!handle)
{
cerr << "Couldn't load library ):" << endl;
return 1;
}
EClass * (*GetEClass)();
void * (DeleteEClass)(EClass *);
GetEClass = (EClass* (*)())dlsym(handle, "GetEClass");
EClass *a = (EClass *) GetEClass();
a->func();
return 0;
}
Собирается файл строкой g++ -o lu -ldl lu.cpp. Ключ -ldl подключает библиотеку, в которой находятся dlopen и другие функции для работы с динамическими библиотеками.
вторник, 14 февраля 2012 г.
Как собрать и подписать программу для Android
Для того, чтобы выкладывать приложения для Android на Android Market, необходимо иметь подписанный apk. При чем, все версии программы следует подписывать одним и тем же ключом, иначе свежую версию программы Android Market выложить не позволит.
Подписаться на:
Сообщения (Atom)