2010/12/22

Niewinne static

Czym różną się zmienne globalne oznaczone jako static:
- ich definicja nie jest dołączana do tablicy exportu
- są inicjalizowane tylko raz (podczas uruchomienia kodu startowego, domyślnie 0 (sekcja bss) lub wartością podana przy deklaracji (sekcja .data))

O ile pierwsza właściwość jest mało inwazyjna to druga ma pewne konsekwencje jeśli o niej zapomnimy.
Gdybyśmy np chcieli pisać pseudo obiektowo wykorzystując czyste C, i zapomnieli o konstruktorze statycznym a uprościli sprawę inicjalizujac zmienne współdzielone w miejscu deklaracji.

Np załóżmy ze mamy do napisania prosta klasę która ma jedna zmienna współdzielona przez wszystkie instancje oraz funkcje Create, Destroy i DoSome.

static int mod_state_variable = 10; //dla uproszczenia pomijam mutexy
typedef struct Mod_Tag
{
      int some_var;
} Mod_T;

void Mod_Creat(Mod_T *mod)
{

    mod->some_var = 0;
}

void Mod_Destroy(Mod_T *mod)
{
}

void Mod_DoSome(Mod_T *mod)
{
   if( 10 == mod_state_variable )
       mod_state_variable = 50;
   mod_state_variable++;
   mod->some_var++;
}

sekwencja
Mod_Init();
Mod_DoSome();
Mod_DoSome();
Mod_Finalize();

da wynik
mod_state_variable = 51 mod->some_var = 1 po pierwszym DoSome
mod_state_variable = 52 mod->some_var = 2 po drugim DoSome

powtórzenie sekwencji
Mod_Init();
Mod_DoSome();
Mod_DoSome();
Mod_Finalize();

da nam
mod_state_variable = 53 mod->some_var = 1 po pierwszym DoSome
mod_state_variable = 54 mod->some_var = 2 po drugim DoSome

ponieważ zmienna statyczna mod_state_variable inicjalizowana jest tylko raz.
Jeśli chcemy przywrócić pierwotny stan zmiennej współdzielonej musieli byśmy użyć coś na wzór konstruktora statycznego.

Podobnie, inicjalizacja w miejscu deklaracji nie spełni swojego zadania np w przypadku bibliotek dynamicznych które posiadają tak inicjalizowane zmienne statyczne. Dopiero odłączenie biblioteki i ponowne jej podłączenie spowoduje przeinicjalizowanie takich zmiennych.

2010/10/14

Amnezja

Czasami mam wrażenie że metodą optymalizacji zapominam co mniej istotne aspekty. Kiedyś już chyba głowiłem się nad zagadnieniem przekazywania tablic w parametrach funkcji.

Przywykłem do tego ze tablice deklarujemy w parametrach funkcji jako
fkt(int tab[])

W kodzie kolegi zobaczyłem
fkt(int tab[10])

Pierwsze skojarzenie jakie mi się nasunęło, to że ta tablica przejdzie przez stos jako kopia pamięci (40bajtow)...

Okazalo sie ze jest inaczej:
#include

struct ss {
    int field1;
    int field2;
    int tab[100];
};

void fkt(char tab[10])
{
    printf("%p\n", tab);
}

void fkt2(struct ss param)
{
    printf("%p\n", &param);
}

int main()
{
    char tab[10] = { 0, 1, 2 };
    char tab2[] = { 1, 1, 1};
    struct ss param;

    fkt(tab);
    printf("%p\n", tab);
    fkt(tab2);
    printf("%p\n", tab2);

    fkt2(param);
    printf("%p\n", &param);

    return 0;
}


Wynik:
[xzs6ts@TVBuildAlfa BWL]$ ./a
0xbfa01916
0xbfa01916
0xbfa01913
0xbfa01913
0xbfa015d0
0xbfa01778


Dlaczego przekazywanie struktur przez stos jest wykonywane jako kopia a tablic jako referencja ?
"nazwa zmiennej tablicowej jest jednoczenie wskaźnikiem do pierwszego elementu"
Z tego tez powodu w języku C nie możemy powiedzieć "przekaz tablice", bo "się po prostu nie da" :)
Za to możemy powiedzieć "przekaz strukturę" co tez kompilator czyni.

2010/09/10

Jak zawiesic programiste ?

Uff było ciężko ...

Problem jest taki, mamy taki niewinny kod:

#include

int get_val(const int **pp)
{
    return **pp;
}

int main()
{
    int v = 10;
    int *t[] = { &v };

    printf("%i\n", get_val(t) );
}


Kompilator w linii z printf zgłasza błąd ? Dlaczego, przecież nie robię nic złego :). Deklaruje tablice wskaźników do int o wielkości jednego elementu (jeden wskaźnik), i chce go przekazać wskaźnik do tej tablicy do funkcji która zwraca wartość; Funkcja nie modyfikuje zawartości elementów wiec dodajemy const, tak dla zasady :) (bo w firmie wymagają żeby dawać const)

Poniższa strona nie za bardzo mnie przekonała:
http://www.parashift.com/c++-faq-lite/const-correctness.html#faq-18.17

Wolałem sobie to wytłumaczyć następująco:
#include

const v = 0;
const int *p = &v;

int get_val(const int **pp)
{
    *pp = p;
    return **pp;
}

int main()
{
    int v = 10;
    int *t[] = { &v };

    //printf("%i\n", get_val(t) );

    *(t[0]) = 20; //tutaj teoretycznie modyfikujemy lokalna zmienna, a tak naprawdę funkcja podmieniła wskaźnik i modyfikujemy const ... otrzymujemy SIGSEG
    printf("%i\n", v );
}


Teraz ewidentnie widać dlaczego rzutowanie int ** na const int ** jest zabronione :)
Bład w stwierdzeniu jest następujący:
Deklaruje tablice wskaźników do int o wielkości jednego elementu (jeden wskaźnik), i chce go przekazać wskaźnik do tej tablicy do funkcji która zwraca wartość. Funkcja nie modyfikuje zawartości elementów ALE MOŻNE MODYFIKOWAĆ ZAWARTOŚĆ TABLICY :), w szczególności podmienić wskaźnik na coś czego zmieniać nie wolno (a co jest poprawnym adresem procesu).

PS: A mówią ze stałe wskaźniki są niepopularne
PS2: Teraz już wiem gdzie są wykorzystywane :P. Wykorzystywane są do męczenia biednych developerów :D
PS3: Wymiękam ... dlaczego poniższe jest problemem ? HELP!!!
int main()
{
    int v;
    int * const p = &v;
    const * const **pp = &p;
}

2010/08/25

Rozmowa kwalifikacyjna

Pytania z serii "rozmowa kwalifikacyjna"

jaka jest różnica między poniższymi deklaracjami tab

int function(int tab[])
{
...
}

struct SomeStruct_T
{
   int tab[];
};

Odpowiedz:
deklaracja w parametrze funkcji nie alokuje pamięci na stosie, jest ona równoważna z deklaracja function(int *tab)
deklaracja w strukturze również nie alokuje pamięci ale dostęp do pola tab będzie się odbywał poprzez referencje do pamięci znajdującej sie bezpośrednio za struktura, w ten sposób można tworzyć np tablice o zmiennej długości pamiętając o alokowaniu odpowiedniej ilosci pamięci, np na stercie.

jaka jest roznica miedzy poniższmi deklaracjami field

struct SomeStruct
{
   union field
   {
      int a;
   };
}

struct SomeStruct
{
   union
   {
      int a;
   } field;

}

Odpowiedz:
pierwsza to czysta deklaracja unii o nazwie field, struktura nie allokuje przestrzeni na zadne pole
druga to deklaracja pola field o typie unii anonimowej, struktura będzie miała rozmiar sizeof(int)

2010/07/06

Dlaczego zamkniete oprogramowanie jest passé

Oto odpowiedz dlaczego producenci oprogramowania powinni gwarantować bezpieczeństwo swoich produktów. Kto wie ... może kiedyś :)

http://www.heise-online.pl/newsticker/news/item/Luki-Microsoftu-raz-Full-Disclosure-a-raz-Null-Disclosure-1033694.html

2010/06/29

SIGSEGV

Gdyby ktoś potrzebował kodu obsługującego SIGSEGV w aplikacji:

gcc -rdynamic

#define _GNU_SOURCE
#include
#include
#include
#include

----------- SIGSEG!!! -----------
Fault addr [0x00000001] in function [0x00416d94] FKT_BL_Creat+0x32
-------- Backtrace start --------
Obtained 8 stack frames.
0 : [0x00408018] pthread_create+0x2d2
1 : [0x2956e420] __kernel_rt_sigreturn+0x0
2 : [0x00416d94] FKT_BL_Creat+0x32
3 : [0x00415fcc] Fkt_Tuning_Init+0x90
4 : [0x00408018] pthread_create+0x8d8
5 : [0x00408018] pthread_create+0x654
6 : [0x0043123c] unresolved
7 : [0x2958559e] unresolved
Aborted

static void sigseg_hndlr(int unused(signum), siginfo_t* siginfo, void* ucont)
{
   void * array[50];
   size_t size;
   size_t i;
   ucontext_t *ucontext = (ucontext_t*)ucont;
   void* pc = (void*)(ucontext->uc_mcontext.gregs[REG_EIP]); /* for x86 */
   Dl_info dlinfo;

   printf("----------- SIGSEG!!! -----------\n");
   if( dladdr(pc, &dlinfo) && (NULL != dlinfo.dli_sname) )
      printf("Fault addr [0x%08x] in function [0x%08x] %s+0x%x\n", (unsigned int)(siginfo->si_addr), (unsigned int)(dlinfo.dli_saddr), dlinfo.dli_sname, pc - dlinfo.dli_saddr );
   else
      printf("Fault addr [0x%08x] in function [0x%08x] unresolved\n", (unsigned int)(siginfo->si_addr), (unsigned int)(pc));

   printf("-------- Backtrace start --------\n");
   size = backtrace(array, 50);
   printf ("Obtained %zd stack frames.\n", size);
   for (i = 0; i < size; i++)
   {
      if( dladdr(array[i], &dlinfo) && (NULL != dlinfo.dli_sname) )
         printf("%d : [0x%08x] %s+0x%x\n", i, (unsigned int)(dlinfo.dli_saddr), dlinfo.dli_sname, array[i] - dlinfo.dli_saddr );
      else
         printf("%d : [0x%08x] unresolved\n", i, (unsigned int)(array[i]));
   }

   fflush(stdout);
   abort();
}


int main(int argc, char* argv[])
{
   SAL_Config_T sal_config;
   SAL_Thread_Attr_T thread_attr;
   int retv = -1;

   sigaction(
      SIGSEGV, /* int signum, */
      &sigsegact, /* const struct sigaction *act, */
      NULL /* struct sigaction *oldact */ );
}

2010/06/25

.Niet

Wyobraź sobie świat, w którym nie mógł byś naprawiać rzeczy które cię otaczają ? Weźmy np twój samochód, wyobraź sobie że właśnie się zepsuł i jedynym sposobem aby go naprawić, jest oddanie do warsztatu. Nie jesteś w stanie zdobyć żadnych rysunków czy schematów. Zepsuł ci się odkurzacz? masz pecha, bo nie da się go otworzyć i naprawić, musisz czekać 2 tygodnie na serwis.

Co w tym dziwnego, skoro tak właśnie zaczyna działać rynek? Moim zdaniem to wygodnictwo, przyzwyczaja nas do "niemyślenia". Nie musisz wiedzieć jak coś jest skonstruowane, żeby tego używać, ale gdy skończy się gwarancja, skazany jesteś na zakup nowego produktu.

Po co ten wywód ? Ot tak właśnie działa obecny rynek oprogramowania. Od 4 kwietnia nie istnieje wsparcie dla Windows Xp a łatki bezpieczeństwa wydawane będą do 4 sierpnia 2014r. Długo ? Weźmy pod uwagę nowy sprzęt. Już teraz widać jak Xp odstaje. Nie zobaczymy na nim DirectX 10 ani sterowników USB3.0. Zapomnij więc np o nowych kartach graficznych i szybkich pamięciach przenośnych. Tak właśnie M$ zmusza nas do kupowania nowych produktów, aby zachować ciągłość przychodów.
Niepokojące jest też to, że firmy takie jak M$ wypuszczają własne produkty przeznaczone dla programistów: biblioteki i narzędzia. Przykładem niech będzie Apple i ich framework do iPhone. Chcesz sprzedawać swoje produkty ? musisz kupić nasze biblioteki? To jest naprawdę chore, nie dość że dobrowolnie zgadzam się na wsparcie waszej technologi, to jeszcze muszę opłacać jakiś haracz ? To samo jest z .Niet Mobile. Albo kupujesz M$ Visual Studio w wersji Professional, albo piszesz w notatniku :). Masakra ... niedługo może będę musiał płacić za poprawki bezpieczeństwa ?

Zmierzając do meritum, dlaczego nie lubię .Niet ? Podobnie jak z oprogramowaniem użytkowym i porównaniem do obecnego trendu rynku konsumenckiego jesteś skazany na używanie "jednego słusznego API". Dokumentacja też pozostawia wiele do życzenia. Pomijając cała masę bugów które uprzykrzały mi życie przez ostanie 2 lata, .Niet jest strasznie niewygodny (API jest jakieś skrzywione). Cokolwiek chcesz zrobić "po swojemu" wbrew "jedynej słusznej drodze", napotykasz problemy.

Dlaczego lubię OpenSource ? Ponieważ nigdy nie czujesz się skrepowany, masz pełny dostęp do źródeł. Jeśli coś nie działa tak jak chcesz, zawsze możesz przerobić API, poprawić błąd w bibliotece lub poprostu "zobaczyć pod maskę". O to właśnie chodzi w programowaniu, o radość płynąca z uczenia się na błędach, modyfikacji i wzorowaniu się na pracy innych. Do niczego nie jesteś zmuszany. Nie odpowiada ci jakaś biblioteka ? jest tysiące innych. Tak właśnie powstają dobre standardy, nikt ich nie narzuca, one same "wypływają na wierzch" bo są po prostu dobre. To nie jest .Niet "jedynie słuszna droga". Co więcej, jeśli masz odmienny pomysł na rozwiązanie danego problemu, możesz podzielić się nim z innymi. Ciągłe doskonalenie i wymiana doświadczeń jest podstawa idei OpenSource.

Ludzie którzy głoszą "nie da się zarobić na otwartym oprogramowaniu" są dla mnie fanatykami. Moja firma już od kilku lat współpracuje z firmami oferującymi support dla produktów OpenSource, a nawet zatrudniamy programistów ze świata OpenSource, aby dla nas przygotowali modyfikacje ich kodu. OpenSource nie oznacza FreeSoftware jak większości się wydaje.

Dlaczego o tym pisze ? Bo dziwi mnie ze tak wielu programistów dobrowolnie oddaje swoje "samochody" i "odkurzacze" do serwisu. Godzą się na to, zamiast być ciekawym (moim zdaniem podstawowa cecha dobrego programisty). Nie zadają sobie pytania "dlaczego?" tylko "kiedy?". "Kiedy ten problem zniknie żebym mógł skończyć moją robotę" albo "Jak ominąć ten BUG żeby to jednak działało" i tak od przypadku do przypadku.
Niepokojące jest też to, że duże firmy IT zachęcają studentów do uczenia się i używania swoich produktów, aby już na starcie ich kariery zapewnić sobie przyszłych klientów. Oni przecież będą używać tych bibliotek, produkować swoje oprogramowanie bazując na tych technologiach. Przez takie programy jak MSDNAA, M$ niskim kosztem zapewnia sobie bardzo dobrą pozycje na rynku. Uważam to za złą praktykę jakiekolwiek są z tego korzyści dla studentów. To samonapędzający się mechanizm. .Niet jest popularny, więc znać go wypada (może przyda się w przyszłej pracy). A później chcąc nie chcąc, wracamy do tego co już znamy i popularyzujemy dalej, napędzając kasę do kieszeni M$. Nie wiem dlaczego, ale na moich studiach nie było zajęć, na których omawiano by biblioteki/rozwiązania OpenSource. Dlatego właśnie uważam to za szkodę dla samych studentów.

Na studiach wydawało mi się że, OpenSource to coś lepszego. To słowo miało w sobie jakąś wyższą idee, którą (czasami na siłę) starałem się przekazać innym :). Dzisiaj mogę z czystym sumieniem powiedzieć że na OpenSource nie trzeba "nawracać", tym się po prostu zaraża :). Wszystkie moje znaczące projekty które oparłem na OpenSource zaliczam do sukcesów, te oparte na rozwiązaniach komercyjnych do mniejszych lub większych porażek. Moja ocena wynika z czystej kalkulacji czasu i nerwów jakie poświęciłem.

Słowo kończące: możesz się nie zgadzać z opiniami tu wyrażonymi, jeśli wygodnie ci z M$ po prostu zostań tam gdzie jesteś :)

EDIT: heh ... nie tylko ja jestem zdania ze .Niet :D, oto wersja multimedialna ... .Not https://www.youtube.com/watch?v=RnqAXuLZlaE

2010/06/22

Odruch wymiotny M$ patch instalatora

Dzisiaj wyskoczył mi monit o zainstalowanie latki  KB976576. Widziałem już rożne głupoty M$, ale ta jest wyjątkowo polityczna :)

"Zainstalowanie tej aktualizacji pozwala uniknąć konieczności ponownego uruchamiana systemu w większości przypadków po zainstalowaniu programu .NET Framework 4 i nowszych wersji. Występują pewne znane problemy z podkładkami zawartymi w programie .NET Framework 2.0 z dodatkiem Service Pack 2, które uniemożliwiają im poprawne przekierowywanie wywołań do odpowiedniej wersji programu .NET Framework. W wyniku tego aplikacje utworzone z zastosowaniem nowszych wersji programu .NET Framework, na przykład programu .NET Framework 4, wymagają zaktualizowania tych często używanych podkładek, co skutkuje wymaganiem ponownego uruchomienia systemu. Po zainstalowaniu tego elementu może być konieczne ponowne uruchomienie komputera."

Restartować czy nie restartować, ot nie mogę się zdecydować :P


Sztuczny bełkot zamiast rzeczowego opisu problemu. Nie wiem kto zawinił, tłumacz czy autor tego tekstu, ale z powyższego opisu nie sposób wywnioskować czego naprawdę dotyczy łatka. W każdym razie jeśli mieliście ostatnimi czasy problemy z łatkami które mimo instalacji ciągle wracały, to (o ile tym razem wierzyć M$) ta poprawka ma zakończyć wasze męki :)

2010/05/24

Windows GDI, czyli jak nowe jest lepsze niż stare

Taki oto news przeczytałem:

http://www.heise-online.pl/security/news/item/Microsoft-ostrzega-przed-krytyczna-luka-w-64-bitowej-wersji-Windows-7-1003325.html

Z jednej strony BUG, z drugiej wymijające tłumaczenie M$ które można przeczytać na tej stronie:
http://www.microsoft.com/technet/security/advisory/2028859.mspx

Ciekawsze fragmenty:
What is the Canonical Display Driver (cdd.dll)?
The Canonical Display Driver (cdd.dll) is used by desktop composition to blend GDI and DirectX drawing. CDD emulates the interface of a Windows XP display driver for interactions with the Win32k GDI graphics engine.

Czyli nie tylko ja pisze nowe, lepsze, szybsze :D

oraz:
What might an attacker use this vulnerability to do?
In most scenarios, an attacker who successfully exploited this vulnerability could cause the affected system to stop responding and automatically restart.

Why is code execution unlikely for this issue?
An attacker who attempts to exploit this issue for code execution would need to write executable content to a specific space in kernel memory. However, since the starting address will be random, the final pointer destination will be difficult to predict. The implementation of Address Space Layout Randomization (ASLR) by default on affected systems further complicates this prediction. In most scenarios, exploit code could much more likely result in a denial of service than in code execution.

What is Address Space Layout Randomization (ASLR)?
Systems implementing Address Space Layout Randomization relocate normally-predictable function entry points pseudo-randomly in memory. Windows ASLR re-bases DLL or EXE into one of 256 random locations in memory. Therefore, attackers using hardcoded addresses are likely to "guess correctly" one in 256 times. For more information regarding ASLR, visit the TechNet Magazine article, Inside the Windows Vista Kernel: Part 3.

Czyli ... drogi kliencie, kupując Windows 7 jesteś narażony na atak z dowolnej strony WWW. Znowu daliśmy d... tak jak kiedyś ze biblioteka do przetwarzania obrazów JPG (http://www.microsoft.com/technet/security/bulletin/ms04-028.mspx), ale nie przejmuj się. Mamy przecież ASLR który umieszcza kod kernela w jednym z 256 lokacji, jesteś więc bezpieczny bo dobra ściema nie jest zła.
http://www.heise-online.pl/newsticker/news/item/Nowa-metoda-exploitowa-do-omijania-ochrony-pamieci-960185.html

2010/04/29

Jeśli używacie kompilacji z warunkową optymalizacją, może okazać się że przeoczycie błędy w waszym kodzie


size_t calc_segcnt(size_t *ret_segcnt)
{

   size_t segcnt;

   ...


   while( cond )
   {
      segcnt = blablabla
   }
   if( ret_segcnt )
         *ret_segcnt = segcnt;


   ...


}


Przy wyłączonej optymalizacji kompilacja przejdzie bez ostrzeżeń. Po włączeniu optymalizacji otrzymacie:
warning: “segcnt” may be used uninitialized in this function

Inicjalizacja segcnt jest zalezna, od „cond” który może się nie wykonać, a puzniej mamy warunkowe przypisanie pod adres wyłuskany ze wskaznika. Podczas optymalizacji widocznie kompilator chce uprościć kod i wykrywa niezainicjalizowana zmienna. Brak optymalizacji widocznie nie wywołuje kodu sprawdzającego ścieżki inicjalizacji.

2010/04/07

OOXML: Wyszlo szydło z wora

Od jakiegoś czasu M$ stara się przepchnąć format plików używany przez pakiet Office jako standard ISO. Standard zatwierdzono warunkowo co wzbudzało wiele kontrowersji.

Do tej pory M$ nie tylko nie poprawił błędów w standardzie a nawet nie przygotował wzorcowej implementacji (Nowy Office 2010 nadal używa tych samych formatów co wersja poprzednia).

Myślę że na światło dzienne wyszły prawdziwe motywy M$ (kasa za sprzedane licencje oczywistego kandydata używającego OOXML) jak i jakość jego produktów. Skoro M$ tak dba o poprawienie własnego standardu nie sądzę aby zależało im na samej standaryzacji a raczej na profitach.

Więcej informacji:
http://www.heise-online.pl/open/news/item/OOXML-format-Microsoftu-przepadl-w-testach-standaryzacyjnych-972157.html
http://www.heise-online.pl/open/news/item/ISO-odpiera-zarzuty-w-sprawie-przyjecia-OOXML-a-773080.html
http://www.heise-online.pl/open/news/item/Microsoftowy-format-OOXML-bedzie-standardem-ISO-762624.html


I na koniec coś z naszego podwórka (mądrych mamy decydentów)
http://www.heise-online.pl/open/news/item/PKN-Polska-za-OOXML-jako-standardem-ISO-762602.html

2010/04/02

64bit vs 32bit

Dzisiaj poprawiałem bugi w Dbe które ujawniły sie dopiero na 64bitowej maszynie. Dla treningu popełniłem też taki program:

#include
#include

int main()
{
    int i = -1;
    long l = i;
    unsigned long ul = i;
    enum {
        zero = 0
    };

    printf("sizeof(i) = %zi, sizeof(l) = %zi\n", sizeof(i), sizeof(l));
    printf("sizeof(zero) = %zi\n", sizeof(zero));
    printf("sizeof(size_t) = %zi\n", sizeof(size_t));
    printf("l = i -> %lx\n", l);
    printf("(long)i -> %lx\n", (long)i);
    printf("(long)-1 -> %lx\n", (long)-1);
    printf("-1L -> %lx\n", -1L);
    printf("ul -> %lx\n", ul);

    i = l;
    printf("i = l -> %x\n", i);

    return 0;
}


Wyniki:

sizeof(i) = 4, sizeof(l) = 8
sizeof(zero) = 4
sizeof(size_t) = 8
l = i -> ffffffffffffffff
(long)i -> ffffffffffffffff
(long)-1 -> ffffffffffffffff
-1L -> ffffffffffffffff
ul -> ffffffffffffffff
i = l -> ffffffff

Natrafiłem też na taki dokument: http://www.ibm.com/developerworks/library/l-port64.html. Oto ciekawsze fragmenty:

Declarations
To enable your code to work on both 32-bit and 64-bit systems, note the following regarding declarations:
  • Declare integer constants using "L" or "U", as appropriate.
  • Ensure that an unsigned int is used where appropriate to prevent sign extension.
  • If you have specific variables that need to be 32-bits on both platforms, define the type to be int.
  • If the variable should be 32-bits on 32-bit systems and 64-bits on 64-bit systems, define them to be long.
  • Declare numeric variables as int or long for alignment and performance. Don’t try to save bytes using char or short.
  • Declare character pointers and character bytes as unsigned to avoid sign extension problems with 8-bit characters.
Expressions
In C/C++, expressions are based upon associativity, precedence of operators and a set of arithmetic promotion rules. To enable your expression to work correctly on both 32-bit and 64-bit systems, note the following rules:
  • Addition of two signed ints results in a signed int.
  • Addition of an int and a long results in a long.
  • If one of the operands is unsigned and the other is a signed int, the expression becomes an unsigned.
  • Addition of an int and a double results in a double. Here, the int is converted to a double before addition.

Bit shifting
Untyped integral constants are of type (unsigned) int. This might lead to unexpected truncation while shifting.
For example, in the following code snippet, the maximum value for a can be 31. This is because the type of 1 << a is int.
long t = 1 << a;
To get the shift done on a 64-bit system, 1L should be used as shown below:
long t = 1L << a; 


Oraz taki dokument http://www.unix.org/version2/whatsnew/lp64_wp.html gdzie można znaleźć uzasadnienie dla modelu LP64:

2012

Strach, terror, ogień i flaki ... 2012 nadchodzi.
A tak poważnie to czemu akurat 2012. Z powodu jakiś indiańców po których został tylko kalendarz zawijający się na 2012?

W dobie wszechobecnej informatyzacji bardziej obawiał bym się innych dat.
http://www.ibm.com/developerworks/library/l-port64.html
"In Linux, dates are expressed as signed 32-bit integers representing the number of seconds since January 1, 1970. This turns negative in 2038"
http://en.wikipedia.org/wiki/Year_2038_problem

Pomyśl więc zanim kupisz nowa lodówkę lub mikrofalówkę z systemem operacyjnym. (Słyszałem nawet ze Linux będzie instalowany w spłuczkach toaletowych). 19 stycznia 2038 o 3:14 możesz być zaskoczony gdy zabraknie prądu w gniazdku i wody w kranie (w toalecie też zabraknie więc nie myśl że to cię uratuje :D).

Tak więc ludzkości, oto jaki zgotowałaś sobie los ...

Update: przejście na 64bitowe systemy tylko odroczy ten problem do 4 Grudnia roku 292,277,026,596 !!! Apokalipsa! :)

Powrót do przeszłości ?

Mam wrażenie że pojęcie komputera osobistego coraz bardziej nabiera na znaczeniu. Wydarzenia takie jak ewenement "iPada" czy nowe technologie w procesorach (optoelektronika) coraz wyraziściej zaznaczają przepaść między wydajnością komputerów osobistych a serwerów. Jeszcze parę lat temu te same  komponenty były używane do budowy serwerów czy całych gridów jak i desktopów. Obecnie wracamy do korzeni. Małe osobiste komputerki służące jako maszyny do pisania kontra super wydajne centra obliczeniowe zajmujące całe pomieszczenia. I nie chodzi mi o to że takie systemy nie istniały w latach 90, raczej o to, jak były popularne. Jeszcze kilka lat temu każda większa firma posiadała własną serwerownie, obecnie jest to po prostu nieopłacalne. Po co zatrudniać ludzi i kupować sprzęt skoro można wydać połowę kwoty i wydelegować nasze aplikacje do chmury ?
Idąc za modnym hasłem jednego z producentów "komputer osobisty jest teraz naprawdę osobisty" a w najbliższych latach sądzę że będzie tylko terminalem lub prostą maszyna do pisania.

Aby posłużyć się przykładem:
http://openzone.pl/news,twoje-dane-w-chmurze-czym-jest-cloud-computing,2574
http://www.heise-online.pl/newsticker/news/item/Intel-przedstawia-osmiordzeniowy-procesor-serwerowy-968106.html

Pierwsze wrażenie ... hmmm sami oceńcie za ile lat będziecie mieli do dyspozycji 1TB RAMu obsługiwany przez jeden tylko procesor ? ;)
Dlatego właśnie ... mamy powrót do przeszłości :)

Na koniec konkursik:
IBM System/370 rok 1971


Peak Server Room, czas obecny
Znajdź różnice ;)

2010/03/26

QT

Właśnie skończyłem się bawić mała aplikacyjna w QT, która miała za zadanie wyświetlać dane z bazy PostgreSQL. Jestem zaskoczony jak szybko i łatwo pisze się aplikacje w QT. Po przejściach z pracą dyplomowa i .Net jestem w stanie się założyć o każde pieniądze że to co do tej pory robiłeś w .Net w QT zrobisz 2 razy szybciej. Oto dowód, kompletna aplikacja do edycji danych z poprzez ODBC w formie podobnej do arkuszu kalkulacyjnego Excel. 85 linij kodu źródłowego.


class EditableSqlModel : public QSqlQueryModel
{
Q_OBJECT

public:
EditableSqlModel(QObject *parent = 0);

Qt::ItemFlags flags(const QModelIndex &index) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);

private:
void refresh();
};

int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QSqlDatabase db = QSqlDatabase::addDatabase("QODBC");
db.setDatabaseName("PostgreSQL_ip");

if (!db.open()) {
QMessageBox::critical(0, qApp->tr("Cannot open database"),
qApp->tr("Unable to establish a database connection.\n", QMessageBox::Cancel);
return -1;

EditableSqlModel editableModel;
QTableView *view = new QTableView;
view->setModel(editableModel);
view->setWindowTitle("Okno do edytowania");
view->show();

return app.exec();
}

EditableSqlModel::EditableSqlModel(QObject *parent) : QSqlQueryModel(parent)
{
refresh();
}

Qt::ItemFlags EditableSqlModel::flags(const QModelIndex &index) const
{
Qt::ItemFlags flags = QSqlQueryModel::flags(index);
if (index.column() >= 1 && index.column() <= 4) flags |= Qt::ItemIsEditable; return flags; } bool EditableSqlModel::setData(const QModelIndex &index, const QVariant &value, int /* role */) { if (index.column() < 1 || index.column() > 4) return false;

QModelIndex primaryKeyIndex = QSqlQueryModel::index(index.row(), 0);
int pkey = data(primaryKeyIndex).toInt();

clear();

bool ok;
QSqlQuery query;
if( 1 == index.column() )
{
query.prepare("update users set parrent = ? where id = ?");
query.addBindValue(value.toInt());
query.addBindValue(pkey);
}
else
{
switch( index.column() )
{
case 2: query.prepare("update users set login = ? where id = ?"); break;
case 3: query.prepare("update users set first = ? where id = ?"); break;
case 4: query.prepare("update users set last = ? where id = ?"); break;
}
query.addBindValue(value.toString());
query.addBindValue(pkey);
}
ok = query.exec();

refresh();
return ok;
}

void EditableSqlModel::refresh()
{
setQuery("select * from users");
}

2010/03/25

Shared Memory

Swego czasu miałem w mojej pracy pewien epizod związany z przekonaniem kolegów do używania pamięci współdzielonej. Jako że był to bardzo oporny proces postanowiłem obrócić go w mały żart :)

2010/03/24

Ligatury

Oto garść informacji o ligaturach.
http://pl.wikipedia.org/wiki/Ligatura_(pismo)

A poniżej (w języku ang.) krótkie streszczenie problemu który napotkałem w mojej pracy w związku z porównywaniem ciągów znakowych zawierających sekwencje znaków z których dana ligatura się składa. Problem polega na tym że klient chce aby litery składowe ligatury były traktowane jako ligatura, co nie jest jednoznaczne, ponieważ takie sekwencje znaków mogą równie dobrze nie tworzyć ligatury, tylko występować swobodnie.

Question: wcscoll does not see that "ß" is equal to "ss" as customer whants


[usr@serv ~]$ export LC_ALL="de_DE.UTF-8"
[usr@serv ~]$ echo "ä" | iconv -f ISO88592 -t ASCII//TRANSLIT
ae
[usr@serv ~]$ echo "ß" | iconv -f ISO88592 -t ASCII//TRANSLIT
ss


wcscoll will not tell that “ß” and “ss” are the same, because that are two different string (coded in UCS). The point is that you don’t know if "ss" means "ss" or "ß" in that place.

The matter of ä = ae ; ss = ß is that in ASCII you cannot code the ß without using special code page. And without special chatters you cannot code all ligatures that occur in specific language. So you use the “replacement” for those chars. Going from ligature into replacement is easy, but the reverse path is not!. It is the same if the “&” sign will be not in ASCII table and you will code it as “et” (that is really the source of & character anyway, combining ‘e’ and ‘t’ – creates a ligature). But no one wants to threat “et” to be equal & because that’s not make sense, they are two different strings.

Kilka przykladowych ligatur:
et & U+0026
At @ U+0040
ſs (lub ſz) ß U+00DF
AE, ae Æ, æ U+00E6, U+00C6
OE Œ, œ, ɶ U+0152, U+0153, U+276
IJ, ij IJ U+0132, U+0133
Ng, ng Ŋ, ŋ U+014A, U+14B
Hv (Hw), hv (hw) Ƕ, ƕ U+01F6, U+0195
DŽ, Dž, dž DŽ, Dž, dž U+01C4, U+01C5, U+01C6 (*)
LJ, Lj, lj LJ, Lj, lj U+01C7, U+01C8, U+01C9 (*)
NJ, Nj, nj NJ, Nj, nj U+01CA, U+01CB, U+01CC (*)
DZ, Dz, dz DZ, Dz, dz, ʣ U+01F1, U+01F2, U+01F3, U+02A3 (*)
lʒ ɮ U+026E
dʒ ʤ U+02A4
dʑ ʥ U+02A5
ts ʦ U+02A6

2010/03/22

Sortowanie leksykograficzne

Z pozoru sortowanie napisów to prosty algorytm. Ot porównujemy sobie literki a każda z nich ma jakich kod, więc można je uszeregować. Hmmm ... i tu wychodzi uwstecznienie polonistyczne. Po pierwsze w grę wchodzą polskie litery, dalej mamy przecież wiele języków, więc musimy pamiętać też o znakach Niemieckich, Czeskich, Francuskich itd (specjalnie nie wymieniłem Chińskiego :D). To nie koniec. Co ze znakami takimi jak spacja i pauza ? Co z dwuznakami i ligaturami ? (Np Niemiecki "umlaut" (SS)).

Chwilowo myślałem więc że problem ten powiązany jest z kodowaniem znaków (np Unicode lub ASCI). Dopiero gdy zauważyłem że każdy język na świecie ma własne zasady ortografii i gramatyki tak więc nie ma czegoś takiego jak jedna kolejność znaków. Innymi słowy gdyby spisać wszystkie nazwy miast na świecie w ich oryginalnej pisowni i posortować je wg zasad Niemieckich, Francuz powiedział by że ta kolejność jest nieprawidłowa. Tak więc jeśli każdemu znakowi przypiszemy unikalną liczbę (co zresztą robi Unicode) to i tak kolejność sortowania nie jest zdefiniowana bez podania konkretnego języka wg zasad którego będziemy sortować. Jak widać kodowanie znaków dla maszyny cyfrowej jest całkiem odrębnym problemem.

Generalnie po kilku godzinach spędzonych nad tematem dogrzebałem się do jednego wniosku: Sortowanie napisów to bardzo skomplikowany problem. Nawet istnieje generalny standard:
http://www.unicode.org/reports/tr10/

Oraz narzędzia do testowania implementacji:
http://demo.icu-project.org/icu-bin/locexp?_=en_US&d_=en&x=col

W szczególności zacytuje poniższy fragment opisujący najczęstsze nieporozumienia wokoło sortowania napisów:
There are a number of common misperceptions about collation.

1. Collation is not aligned with character sets or repertoires of characters. Swedish and German share most of the same characters, for example, but have very different sorting orders.
2. Collation is not code point (binary) order. The simplest case of this is capital Z versus lowercase a. As noted above, beginners may complain about Unicode that a particular character is “not in the right place in the code chart”. That is a misunderstanding of the role of the character encoding in collation. While the Unicode Standard does not gratuitously place characters such that the binary ordering is odd, the only way to get the linguistically-correct order is to use a language-sensitive collation, not a binary ordering.
3. Collation is not a property of strings. Consider a list of cities, with each city correctly tagged with its language. Despite this, a German user will expect to see the cities all sorted according to German order, and not expect to see a word with ö appear after z, simply because the city has a Swedish name. As mentioned above it is of crucial importance that if a German businessman makes a database selection, such as to sum up revenue in each of of the cities from O... to P... for planning purposes, then cities starting with Ö must not be excluded.
4. Collation order is not preserved under concatenation or substring operations, in general. For example, the fact that x is less than y does not mean that x + z is less than y + z. This is because characters may form contractions across the substring or concatenation boundaries. In summary, the following shows which implications not to expect.

x < y does not imply that x+z 
y+z x < y does not imply that z+x < z+y 
x+z < y+z does not imply that x < y 
z+x < z+y does not imply that x < y

5. Collation order is not preserved when comparing sort keys generated from different collation sequences. Remember that sort keys are a preprocessing of strings according to a given set of collation features. From different features, you will get different binary sequences. For example, suppose we have two collations, F and G, where F is a French collation (with accents compared from the end), and G is a German phonebook ordering. Then:
* A ? B according to F if and only if sortkey(F, A) ? sortkey(F, B), and
* A ? B according to G if and only if sortkey(G, A) ? sortkey(G, B)
* But the relation between sortkey(F, A) and sortkey(G, B) says nothing about whether A ? B according to F, or whether A ? B according to G.
6. Collation order is not a stable sort; that is a property of a sort algorithm, not a collation sequence. For more information, see Section 3.4, Stability.
7. Collation order is not fixed. Over time, collation order will vary: there may be fixes that are discovered as more information becomes available about languages; there may be new government or industry standards for the language that require changes; and finally, the new characters that are added to Unicode periodically will interleave with the previously-defined ones. Thus collations must be carefully versioned.

Jeszcze co nieco po Polsku w temacie: http://www.eioba.pl/a87655/sortowanie_leksykograficzne

2010/03/16

NoSQL

Właśnie natknąłem się na coś takiego jak NoSQL:
http://nosql-database.org/
http://en.wikipedia.org/wiki/NoSQL

Spodobał mi się też komentarz:
http://www.linuxjournal.com/article/3294

... almost all [database systems] are software prisons that you must get into and leave the power of UNIX behind. [...] The resulting database systems are large, complex programs which degrade total system performance, especially when they are run in a multi-user environment. [...] UNIX provides hundreds of programs that can be piped together to easily perform almost any function imaginable. Nothing comes close to providing the functions that come standard with UNIX.

The UNIX file structure is the fastest and most readily-available database engine ever built: directories may be viewed as catalogs and tables as plain ASCII files. Commands are common UNIX utilities, such as grep, sed and awk. Nothing should be reinvented.

2010/03/12

Pierwszy post

Czy zawsze aktywujesz ostrzeżenia kompilatora ? Poniższy przykład pokazuje dlaczego są one niezbędne:


int i;
...
if( i < sizeof(int) ) {
   ...
}


Powyższy kod będzie działał tak jak zamierzamy, jeśli "i" będzie przyjmować jedynie wartości dodatnie. Jeśli w "i" znajdzie się liczba ujemna, warunek nie zostanie spełniony, choć matematycznie wszystko wygląda OK. Wynika to z faktu że porównywanie typow signed i unsigned wymusza na kompilatorze rzutowanie do typu unsigned. Z tąd liczba ze znakiem int jest rzutowana do unsigned int. Jak łatwo się domyśleć z -1 robi się 4294967295, co jasno pokazuje ze -1 > 4 :)

Aby otrzymac ostrzeżenie przed tego typu pomyłkami należy w gcc dodać opcje -Wsign-compare lub najlepiej -Wextra która ostrzega nas przed kilkoma innymi błędami. -Wextra jest rozszerzeniem -Wall, samo -Wall nie zawiera -Wsign-compare.

Po dodaniu Wextra prawdopodobnie otrzymamy szereg ostrzeżeń które będziemy chcieli usunąć. Jednym z takich ostrzeżeń są nieużywane parametry funkcji. Jest to dość irytujące ponieważ często zdarza się że celowo nie chcemy wykorzystywać wszystkich parametrów, choćby ze względu na wymuszony format funkcji potrzebnej do wywołania zwrotnego (callback). W takim wypadku możemy posłużyć się poniższym makrem:


#ifdef unused
#elif defined(__GNUC__)
# define unused(x) UNUSED_ ## x __attribute__((unused))
#elif defined(__LCLINT__)
# define unused(x) /*@unused@*/ x
#else
# define unused(x) x
#endif


np:


int fkt(int unused(opt_param)) {
}


Makro można rozszerzyć o obsługę dodatkowych kompilatorów, tak jak zostało to wykonane dla parsera składni LINT.