Konkord na Windowsie - MinGW, Boost

Tagi: boost, C++, cygwin, GCC, kompilacja, konkord, Linux, make, mingw, MSYS, programowanie, Windows,
Kategoria:

Człowiek robi męczące rzeczy z dwóch powodów. Pierwszy powód to czysta ciekawość, a drugi powód to konieczność. Otóż mój kolega posiada Windowsa i chce testować mój program do nauki słówek Konkord, też lubi tak jak uczyć się języków obcych. Niestety nigdy nic nie kompilowałem na Windowsie, musiałem opierać się na skromnych informacjach z Internetu, a najlepsze jest to, że nie było nic po polsku.

MinGW kontra Cygwin

Przechodząc do sedna sprawy, na moim Debianie kompiluję swój program gcc, gdy kiedyś na Windowsie pracowałem, programy kompilowałem MinGW dołączonym do środowiska developerskiego DevC++ (lecz wtedy nie wiedziałem, że używam jakiegoś MinGW). Lecz teraz wiedziałem, że chcą budować aplikację linuksową na Windowsa, mam dwie możliwości, albo zainstalować Cygwina - implementację standardu POSIX dla systemów z rodziny Windows, albo użyć kompilatora MinGW - gcc przeportowanego na systemy z rodziny Windows.

Cygwin zapewniał by mi to, że nie musiałbym zmieniać kodu programu, ani przekompilowywać zewnętrznych bibliotek, których w nim używam, lecz zmusiłbym również tym użytkowników do instalacji Cygwina, a oni raczej nie chcieli by instalować takiego kombajna dla jednego kilkudziesięcokilobajtowego (bez wkompilowanych bibliotek) programu.

MinGW tworzy mi program z rozszerzeniem .exe, który będzie działał na każdym Windowsie i będzie samowystarczalny. Jednak w tym wypadku będę musiał przekompilować biblioteki i je dołączyć do program i czasem zmienić kod programu.

Zdecydowałem się na drugie rozwiązanie, dużo czasu poświęciłem na wstępne przygotowywania, czyli na to, żeby zainstalować i skompilować to, co będzie mi potrzebne do skompilowania programu. Nie żebym aż tak długo się zastanawiał, lecz te pakiety trochę ważą.

...

Przeczytaj cały artykuł i zobacz komentarze

Użycie wskaźnika na elementy vectora

Tagi: błądbłb, błędy, C++, konkord, programowanie, STL, vector,
Kategoria:

Podczas wprowadzenia zmian i testowania programu do nauki słówek wykryłem błąd, który nie był zwykłą literówką, lecz błędem w strukturze programu, pojawiającym się raz na ileś. Taki błąd jest najgorszy, bo trudno odgadnąć, dlaczego to program się wyspuje, jest trudny do uchwycenia. Z tym błędem wiązało się też, że rozwiązując go, musiałem stanąć przed dylematem, które rozwiązanie wybrać. Zaprezentuję przykład, gdzie będzie ten sam błąd

#include 
#include 
using namespace std;
int main() {
	vector elements;
	int **wsk_to_elements = new int*[10000];
	for(int i = 0; i < 10000; i++) {
		elements.push_back(i);
		wsk_to_elements[i] = &elements[i];
	}
	for(int i = 0; i < 10000; i++) {
		elements.push_back(i);
	}
	vector elements2;
	for(int i = 0; i < 100; i++) {
		elements2.push_back(i+10000);
	}
	for(int i = 0; i < 10000; i++) {
		cout << *wsk_to_elements[i] << endl;
	}
	return 0;
}
Niby wszystko w porządku, ale… po skompilowaniu i uruchomienu raczej zobaczymy, że 100 pierwszych wskaźników z tablicy wsk_to_elements wskazuje nam na jakieś elementy, których wartość jest większa od 10000, czyli chyba elementy vectora elements2. Dlaczego? Vector to taki obiekt, który przechowuje nam elementy, pozwala nam dodawać i usuwać elementy w każdej chwili, ale też stara się zachować ciągłość w pamięci, dlatego gdy przy dodaniu 1000 elementu vector widzi, że na nie ma już miejsca na prawo, to przenosi wszystkie elementy do takiego miejsca w pamięci, gdzie będzie mógł dodać ten 1000 element. Krótko mówiąc, nie gwarantuje nam, że elementy będą cały czas w tym samym miejscu w pamięci. Można się przed tym zabezpieczyć rezerwując miejsce na x elementów, dając mu x w konstuktorze, ale przecież nie zawsze wiemy, jaki rozmiar nam będzie potrzebny. Dlatego użycie wskaźników na elementy vectora jest samobójstwem.

I właśnie taki błąd miałem w programie i miałem do wyboru kilka możliwości rozwiązania problemu: I. Posłużyć się iteratorami, ale w praktyce wyglądałoby to tak:

class SingleWord {
	//…
	vector::iterator something;
	//…
}
class Kurs {
	//…
	vector singleWords;
	//…
Trochę głupio uzależniać klasę SingleWord, która ma być niezależna od klas ją wykorzystujących. W porównaniu do drugiego rozwiązania zachowałbym taki sam czas dostępu do elementów. I rozwiązanie nie jest rozwiązaniem, bo ma te same wady, co rozwiązanie oparte na wskaźnikach. Rozwiązaniem podobnym do tego opartego na iteratorach byłoby:
class SingleWord {
	//…
	unsigned int something; //numer słowa w vectorze
	//…
}
class Kurs {
	//…
	vector singleWords;
	//…
To rozwiązanie ma jedną zasadniczę wadę: klasa SingleWord jest zależna od klasy ją wykorzystującej Kurs. II. W samym vectorze posłużyć się wskaźnikami, wyglądałoby to tak:
class SingleWord {
	//…
	SingleWord *something;
	//…
}
class Kurs {
	//…
	vector singleWords;
}
W tym rozwiązaniu klasa SingleWord zachowuje swoją niezależność, ale jest trochę wolniejszy dostęp do elementów z klasy Kurs, bo odbywa się przez wskaźniki. To, że w vectorze są wskaźniki, ma jeszcze inną zaletę, gdy vector będzie zmieniał swoje miejsce w pamięci, nie będzie kopiował ponad 100 bitowego elementu klasy SingleWord, lecz 64 bitowe wskaźniki. Oczywiście nie należy zapomnieć, że tym przypadku musimy samodzielnie zwalniać pamięć, vector.erase() usunie tylko wskaźniki, elementy, na które wskazywały zostaną.

Wybrałem II rozwiązanie, lecz zaskutkowało to tym, że musiałem zmieniać działanie wielu funkcji. Przy okazji tych zmian, stwierdziłem, że gdy chcę odmówić prawa do zmieniania elementu, lepiej zwrócić "wskaźnik na stały element" niż "element", program będzie szybciej działał, ponieważ wskaźnik jest tylko 64 bitowy. Zmieniłem… lecz mocno się zdziwiłem, bo funkcja wygląda tak:

SingleWord const* Kurs::getSingleWord() {
	SingleWord const* something;	
	//…
	return something;
}
, a program skompilował się(a nie powinien) z przypisaniem:
Kurs kurs;
//…
SingleWord sword = kurs.getSingleWord();
//…
Zgłosiem buga na Debianie dla pakietu g++-4.4. Bug nie jest taki straszny, lecz z pewnością utrudnia wykrywanie błędów w programie.

Zobacz komentarze

Konkord 0.1

Tagi: C++, konkord, nauka słówek, program, programowanie, słówka,
Kategoria:

Wyszła wersja 0.1 mojego programu do nauki słówek. Narazie posiada tylko tryb tekstowy. Udało mi się spełnić kilka punktów z listy TODO:

  • Uporządkowałem i zwiększyłem przejrzystość kodu
  • W większości nazwy zmiennych, funkcji, klas pozmieniałem na angielskie
  • Średniozaawansowana obsługa błędów
  • Dodane wyszukiwanie słówek
  • Dodane wczytywanie słówek z pliku
  • Dodałem plik Makefile
Oprócz tego zlikwidowałem wiele błędów. Program się rozwija i pewnie zaniedługo ujrzycie jego kolejną o wiele lepszą wersję. Pobierz Konkord 0.1(kod źródłowy)

Zobacz komentarze

Program do nauki słówek

Tagi: GNU, GNU GPL, języki, konkord, nauka, nauka słówek, program, programowanie,
Kategoria:

Zamierzam napisać o programie do nauki słówek np. z języka angielskiego, który stowrzyłem. Nazwałem go "konkord", chyba dlatego, że wpadłem na pomysł stworzenia tego programu, gdy grałem w gierkę, gdzie jeździ gokardami. Na chwilę obecną ten program jest jeszcze w wersji alfa, więc proszę się liczyć z tym, że korzystanie z niego może przyprawić o ból głowy.

Idea

Uczęszczam do 3 klasy gimnazjum, dla niezoreintowanych, w tej klasie pisze się egzamin gimnazjalny, to oznacza, że jest masa do nauki, do przedmiotów, z których wiedza wymagana przy zdawaniu poszczególnych części tego egzaminu. I tak się składa, że mój rocznik, jako pierwszy pisze test gimnzjalny z języka obcego(ja z angielskiego). Nauczyciel z angielskiego się uwziął i jest masa słówek do wykucia, na próbnym egzaminie nie umknęło moje uwadze, że wymagane są duże zasoby słownictwa. Stwierdziłem też, że metoda, zakrywania dłonią angielskich odpowiedników lub polskich i odpytywanie się choć była wcześniej efektywna, teraz jest nieefektywna, gdyż masę czasu tracę na przepytywanie się ze słówek, które już umię. Więc postanowiłem stworzyć program z mechanizmem, który na podstawie wyników poprzednich przepytywań określałby w jakim stopniu dane słowo umiem, i po jakim czasie je zapomnę, i który przepytywałby mnie z tych słów najmniej opanowanych. A że ja często pomysły wcielam w życie, to więc i ten wcieliłem; po napisaniu 400 linijek silnika nie mogłem się wycofać.

Licencja

Program jest dostępny na licencjiGNU GPL(wersja 3). Zdecydowałem się wybrać tą licencję, ponieważ całkowicie obcja jest mi idea licencji zamkniętych oraz jestem zbyt przywiązany do tego programy, aby go udostępnić na licencji BSD.

Funkcje

Program jest narazie w czesnym stadium rozwoju, określiłbym ten stan jako pre-alpha. Na dziś stworzony jest silnik bez zaawansowanej obsługi błędów, nakładka tekstowa na silnik. Silnik potrafi:
  • tworzyć, zapisywać kurs do pliku oraz wczytywać z pliku,
  • przepytywać ze słówek oraz uczyć nowych słówek,
  • określać w jakim stopniu umi się dane słowa.
Nakładka tekstowa:
  • potrafi obsługiwać kilka kursów naraz,
  • ma rozbudowane menu,
  • nie ma skrotów klawiszowych.
Konkursy się skończyły(zaniedługo pochwalę się wynikami), będę miał więcej czasu, więc udoskonalę program.

Plany

Ogólnie:
  • uporządkować kod,
  • nazwy zmiennych pozmieniać na angielskie,
  • zwiększyć przejrzystość kodu,
  • dodać więcej komentarzy
Silnik:
  • dodać ustawienia programu,
  • dodać osblugę wielu języków,
  • dodać zaawansowaną obsługę błędów,
  • dodać wyszukiwanie słówek po nazwie,
  • dodać dodawanie słówek z pliku.
Nakładka:
  • dodać obsługę skrótów klawiszowych,
  • przenieść nakładkę na bibliotekę ncurses,
  • dodać ustawienia nakładki.
Pobierz program Kompiluje się poleceniem: "g++ main.cpp kurs.cpp -o konkord".

Zobacz komentarze