Go geek!

Our Victory Is Imminent

[C++] Statyczna metoda klasy jako punkt wejścia aplikacji w C++

Skomentuj »

W tym wpisie chciałem napisać o pewnej właściwości linkera MS – punktem wejścia aplikacji może być dowolna funkcja o odpowiedniej sygnaturze – w tym także statyczna metoda klasy! W przypadku aplikacji okienkowej i wykorzystaniu Unicode odpowiednia sygnatura sygnatura wygląda tak

int __stdcall EntryPt(
     HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     WCHAR* lpCmdLine,
     int nCmdShow)

Wystarczy poinformowac o tym linker. W przypadku produktu Microsoftu

link ${OBJS} /SUBSYSTEM:WINDOWS  /ENTRY:EntryPt ${LIBS}

Jak już wspomniałem punktem wejścia może być statyczna metoda klasy

struct WinApp {
     static int __stdcall wWinMain(
          HINSTANCE hInstance,
          HINSTANCE hPrevInstance,
          WCHAR* lpCmdLine,
          int nCmdShow);
}

Oto mały przykład okienkowej aplikacji Win32 której punktem wejścia jest statyczna metoda metoda klasy

#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>

/**
cl -c winapp.cpp

link  winapp.obj /SUBSYSTEM:WINDOWS  /ENTRY:WinApp::wWinMain  kernel32.lib user32.lib gdi32.lib
**/
struct WinApp {
    static int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR* lpCmdLine, int nCmdShow);
    static LRESULT __stdcall WndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};

int WINAPI WinApp::wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, WCHAR* lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc = {
        sizeof(WNDCLASSEX), CS_CLASSDC, WinApp::WndProc, 0L, 0L,
        GetModuleHandle(NULL), NULL,
        LoadCursor( NULL, IDC_ARROW ),
        ( HBRUSH )( COLOR_WINDOW ), NULL,
        "WinApp", NULL };
    RegisterClassEx( &wc );
    HWND hWnd = CreateWindow(
        "WinApp",
        "«Jarosław Przygódzki» Statyczna metoda klasy jako punkt wejścia aplikacji w C++",
        WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 600, 400,
        GetDesktopWindow(), NULL, wc.hInstance, NULL);
    ShowWindow(hWnd, SW_SHOW);
    MSG msg = {0};
    while( GetMessage(&msg, NULL, 0, 0 ))
    {
        TranslateMessage( &msg );
        DispatchMessage( &msg );
    }

    return 0;
}

LRESULT __stdcall WinApp::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg) {
        case WM_CLOSE:
            PostQuitMessage(0);
            break;
        default:
            return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0L;
}

Proces kompilacji i linkowania nie jest skomplikowany

cl -c winapp.cpp
link winapp.obj /SUBSYSTEM:WINDOWS /ENTRY:WinApp::wWinMain kernel32.lib user32.lib
PS

CALLBACK i WINAPI to właśnie aliasy na konwencję wywołania __stdcall

// WinDef.h
#define CALLBACK    __stdcall
#define WINAPI      __stdcall

Deklaracje mogą więc wyglądać następująco

struct WinApp {
     static int WINAPI wWinMain(
          HINSTANCE hInstance,
          HINSTANCE hPrevInstance,
          WCHAR* lpCmdLine,
          int nCmdShow);
    static LRESULT CALLBACK WndProc(
         HWND hWnd,
         UINT uMsg,
         WPARAM wParam,
         LPARAM lParam)
}

I najczęściej tak właśnie wyglądają.

Written by Jarek Przygódzki

Styczeń 19, 2010 at 6:46 pm

Bitowa reprezentacja liczb całkowitych

Skomentuj »

Kilka przydatnych funkcji w różnych językach których wspólną cechą jest pełniona zadanie – wszystkie tworzą binarną reprezentację liczb całkowitych. Zanim przejdę do konkretów (tj kodu źródłowogo) trochę teorii ;P. Sprawdzenie, czy n-ty bit liczby całkowitej w reprezentacji dwójkowej x jest zapalony można zasadniczo wykonać na trzy sposoby – jeden dobry i dwa teoretycznie dobre. Dwie teoretycznie dobre to

  • sprawdzenie czy zapalony jest n-ty bit przez operację koniunkcji bitowej z maską 1 << n
     x & (1 << n) 
  • przesunięcie bitowe x o bitsof(x) - n miejsc w lewo i sprawdzenie, czy zapalony jest najstarszy bit
     (x << n ) & 1 << (bitsof(x) - 1) 

gdzie bitsof(x) ≡ sizeof(type(x)) * BITS_PER_BYTE

Powyższe metody jednak nie są uniwersalne. W większości przypadków typów i języków zadziałają poprawnie. Ale wyobraźmy sobie taką sytuację w języku C++

#define IS_BIT_SET(x, n) ((x)  &  (1 << (n)))
long long x = 1;
bool is32ndBitSet = IS_BIT_SET(x,32); // TRUE, absurd !

Przyczyna błędu jest oczywista, i na całą sytuację prawdopodobnie zwróci nam uwagę kompilator odpowiednim ostrzeżeniem ( w przypadku MSVC będzie to C4334 ). Makro to można naprawić

#define IS_BIT_SET(x, n) ((x)  &  (1LL << (n)))

ale można też spróbować czegoś innego

  • przesunięcie bitowe x o n miejsc w prawo i sprawdzenie, czy najmłodzy bit jest zapalony
     (x >> n) & 0x1
C++
#include <string>

#define IS_BIT_SET(x, n) ((x)  &  (1LL << (n)))
#define SET_BIT(x, n)    ((x) |=  (1LL << (n)))
#define UNSET_BIT(x, n)  ((x) |= ~(1LL << (n)))

template<typename T>
std::string toBinStr(T x) {
	std::string s;
	int bits = sizeof(T) * 8;
	for(int b=bits-1;  b>=0; --b) {
		s+=IS_BIT_SET(x,b)?'1':'0';
	}
	return s;
}
Python
def to_bin_str(x):
	import types
	if type(x) is types.IntType: bits = 32;
	else: raise "Argument must by int type!"
	mask = 1 << bits - 1
	return ''.join('0' if x<<shift & mask == 0 else '1' for shift in range(0,bits))
C#
class BinUtil
{
	public static string toBinStr(int x)
	{
		int bits = 32;
		StringBuilder sb = new StringBuilder(bits);
		for(int i=bits - 1; i>=0 ; i--)
		{
			sb.Append( (x >> i & 0x1 )== 0? "0":"1");
		}

		return sb.ToString();
	}
	public static string toBinStr(uint x)
	{
		int bits = 32;
		StringBuilder sb = new StringBuilder(bits);
		for(int i=bits - 1; i>=0 ; i--) {
			sb.Append( (x >> i & 0x1 )== 0? "0":"1");
		}

		return sb.ToString();
	}
	public static string toBinStr(long x)
	{
		int bits = 64;
		StringBuilder sb = new StringBuilder(bits);
		for(int i=bits - 1; i>=0 ; i--) {
			sb.Append( (x >> i & 0x1 )== 0? "0":"1");
		}
		return sb.ToString();
	}
	public static string toBinStr(ulong x)
	{
		int bits = 64;
		StringBuilder sb = new StringBuilder(bits);
		for(int i=bits - 1; i>=0 ; i--) {
			sb.Append( (x >> i & 0x1 )== 0? "0":"1");
		}
		return sb.ToString();
	}
	public static string toBinStr(byte b)
	{
		int bits = 8;
		StringBuilder sb = new StringBuilder(bits);
		for(int i=bits - 1; i>=0 ; i--){
			sb.Append( (b >> i & 0x1 )== 0? "0":"1");
		}

		return sb.ToString();
	}
}
PS

Tytuł posta może być trochę mylący co do jego treści, ale przecież każdy wie dlaczego int i = -1 ≡ 11111111111111111111111111111111b, prawda?

PS PS

Chyba, że procesor nie stosuje arytmetyki uzupełnień do dwójki. Wtedy oczywiście powyższe stwierdzenie nie jest prawdziwe.

Written by Jarek Przygódzki

Styczeń 19, 2010 at 6:10 pm

Napisane w Programming

Tagged with

[C++] Uniwersalny ekstraktor i inserter dla strumieni binarnych

Skomentuj »

#include <istream>
#include <ostream>
template<class T>
std::istream& read(std::istream& is, T& t) {
        is.read((char*)&t, sizeof(T));
        return is;
}

template<class T>
std::ostream& write(std::ostream& os, const T& t) {
		os.write((char*)&t, sizeof(T));
        return os;
}
template<class T>
std::ostream& operator << (std::ostream& os, const T& t) {
	return write<T>(os,t);
}

template<class T>
std::istream& operator >> (std::istream& is, T& t) {
	return read<T>(is,t);
}

I mały przykład

#include <cstring>
#include <fstream>
struct Superheroine {
		Superheroine(const char* name_ = "", const char* publisher_ = "") {
			strcpy(name,  name_);
			strcpy(publisher, publisher_);
		}
        char name[32];
        char publisher[32];
};
//...
std::ofstream ofs;
ofs.open("data.bin", std::ios::out | std::ios::binary | std::ios::trunc);
Superheroine
	silverFox("Silver Fox","Marvel Comics"),
	natashaIrons("Natasha Irons", "DC Comics");
write<Superheroine>(ofs, silverFox); // write<T>
ofs << natashaIrons; // operator <<
ofs.close();
ifs.open("data.bin", std::ios::in | std::ios::binary);
Superheroine heroine;
ifs >> heroine; // operator >>
// ...
read<Superheroine >(ifs,heroine); // read<T>

Written by Jarek Przygódzki

Grudzień 17, 2009 at 1:37 pm

Napisane w Cpp, Programming

Python i przetwarzanie danych z www

Skomentuj »

Najpierw trzeba oczywiście stronę www pobrać

from urllib2 import urlopen
def get_www(url):
    "Get web page html"
    try:
        content = urlopen(url).read()
        return content
    except:
        return ""

a potem można już zrobić z nią co się chce, np. znaleźć wszystkie odnośniki. Można do tego wykorzystać klasę sgmllib.SGMLParser

from sgmllib import SGMLParser

class URLParser(SGMLParser):
    def reset(self):
        SGMLParser.reset(self)
        self.urls = []
    def start_a(self, attrs):
        href = [v for k, v in attrs if k=='href']
        if href:
            self.urls.extend(href)

html = get_www("http://impact.arc.nasa.gov/")
parser = URLParser()
parser.feed(html)
print parser.urls

Jeśli potrzebujemy czegoś więcej to warto skorzystać z PyXML

Written by Jarek Przygódzki

Październik 28, 2009 at 12:42 pm

Napisane w Programming, Python

MiKTeX + Uft8

Skomentuj »

Dzięki projektowi MiKTeX wykorzystanie LaTeX’a w Windows jest bardzo proste. Jeśli jednak ktoś [tak jak ja] pracuje nad tym samym projektem pod różnymi OS’ami może miec kłopoty. Wiekszośc poradników twierdzi bowiem, ze pod Linuxem należy korzystac z kodowania a Latin-2 (ISO 8859-2) a pod Windows cp1250 (Win Latin 2). Dlaczego nie użyc UTF-8? Poniżej przestawiam szablon dokumentu którego z powodzeniem używam

\documentclass[a4paper]{article}
\usepackage[utf8]{inputenc}
\usepackage[OT4]{polski}
\usepackage{bera}
\begin{document}
\end{document}

Trzeba tylko uważac, żeby plik źródłowy nie zawierał BOM (byte order mark).

Written by Jarek Przygódzki

Sierpień 31, 2009 at 7:01 am

Napisane w Uncategorized

[C++] Użycie freopen do przekierowania standardowych strumieni

Skomentuj »

Za pomocą funkcji

#include <cstdio>
FILE *freopen(const char *filename, const char *mode, FILE *stream);

możemy dokonac przekierowania standardowych strumieni (stdin, stdout, stderr), co w pewnych sytuacjach może byc bardzo pomocne.

freopen("stdout.txt", "w", stdout);
freopen("stderr.txt", "w", stderr);

Written by Jarek Przygódzki

Lipiec 16, 2009 at 6:11 am

Napisane w Cpp, Programming

Tagged with

[Java] static import

Skomentuj »

Jedną z nowych rzeczy dodanych w Javie 1.5 jest statyczny import.  Umożliwia on dostęp do statycznym metod i pól klasy bez odwoływania się do jej nazwy. Jest on szczególnie przydatny w przypadku klas użytkowych takich jak np java.lang.Math. Możemy wówczas napisać

import static java.lang.Math.*;
//
double r = cos(PI * theta);

zamiast

double r = Math.cos(Math.PI * theta);

Nie jest to może rewolucja, ale cecha w pewnych sytuacjach bardzo przydatna.

Written by Jarek Przygódzki

Czerwiec 29, 2009 at 11:12 am

Piknik Prawdopodobieństwa i Statystyki

Skomentuj »

Written by Jarek Przygódzki

Czerwiec 16, 2009 at 9:54 am

Napisane w Uncategorized

Właściwości w C++

Skomentuj »

No coż, w standardzie ich po prostu nie ma. Niektóre kompilatory, jak np mój ulubiony MSVC oferują je za pomocą rozszerzeń, inne nie oferują ich wcale. Wspomniany już kompilator MS wspiera je jednak znakomicie.

Składnia jest prosta

__declspec (property (get=nameOfGetFunction, put=nameOfSetFunction)) type propertyName;

np

class Renderer {
private:
     ID3D10Device* m_pDevice;
     ID3D10Device& GetDevice(){ return *m_pDevice;}
public:
     __declspec (property (get=GetDevice)) ID3D10Device& Device;
}

Szablony? Oczywiście.

template<class T>
class vec3 {
public:
    inline T get_x() const { return m_v[0]; }
    inline T get_y() const { return m_v[1]; }
    inline T get_z() const { return m_v[2]; }

    inline void set_x(T value) { m_v[0] = value; }
    inline void set_y(T value) { m_v[1] = value; }
    inline void set_z(T value) { m_v[2] = value; }

    __declspec(property(get=get_x,put=set_x)) T x ;
    __declspec(property(get=get_y,put=set_y)) T y ;
    __declspec(property(get=get_z,put=set_z)) T z ;
private:
    T m_v[3];
}

Właściwości wirtualne?


struct Shape {
     float computeArea()=0;
     __declspec(property(get=computeArea)) float Area;
}

struct Rect :  Shape {
    Rect(float w, float h): m_w(w),m_h(h) {}
    float computeArea() {
        return m_w * m_h;
    }
private:
    float m_w, m_h;
}

struct Circle : Shape {
    Circle(float r) : m_radius(r) {}
    float computArea() {
        return M_PI * m_radius * m_radius;
    }
private:
    float m_radius;
}

//...
Shape& s = *new Circle(1.0f);
float area = s.Area;

Oczywiście, świat nie jest idealny, więc i rozszerzenie kompilatora __declspec(property) nie jest, m.in
właściwości nie mogą być statyczne a i z szablonami nie zawsze wszystko działa.
Jeśli ktoś potrzebuje rozwiązań nie ograniczonych do jednego kompilatora, rozwiazanie stanowi biblioteka STLSoft Properties .

STLSoft Getting Started

MSDN property(C++)

Written by Jarek Przygódzki

Czerwiec 4, 2009 at 12:09 pm

WolframAlpha

Skomentuj »

Stephen Wolfram jest naprawdę niewiarygodny !

WolframAlpha

Written by Jarek Przygódzki

Maj 21, 2009 at 6:42 am

Napisane w Geek, Math