Co nowego?

kurs C wersja 0.01

kurs C wersja 0.01

by Administrator Moodle -
Number of replies: 21
Zapraszam do obejrzenia wstępnej wersji kursu programowania w C. Na razie jest to tylko interfejs do moich starych stron www. Będę go stopniowo modyfikował i usprawniał. Pozdrawiam,

Marian
In reply to Administrator Moodle

Odp: kurs C wersja 0.01

by Wojciech Bojewski -
Witam...

"Kompilacja spod edytora TextPad"

... panie doktorze... to nie przystoi, to nie wypada , to sie nie godzi... :-) skoro kurs C to tylko pod linuxa(unixem), bo pod windowsem jest on juz przezytkiem :-)

Spewnoscia bede mial pare pytan odnosnie C... i moje pierwsze pytanie... czy forma zadawania pytan przez moodle bedzie odpowiednia czy tez wolalby pan e-mailem :-) ?

Pozdrawiam Wojciech Bojewski
In reply to Wojciech Bojewski

Odp: Odp: kurs C wersja 0.01

by Marian Rusek -
Dlaczego C pod Windows jest przeżytkiem? Powiedziałbym, że to prędzej Windows jest przeżytkiem :-D C to C niezależnie od systemu, pod którym działa kompilator.

Jeśli zaś chodzi o edytor TextPad, to te zrzuty pochodzą z kursu C, na którym nie mieliśmy zainstalowanych kompilatorów i trzeba było radzić sobie instalując bezpłatny Borland C++ w wersji command line only oraz jakiś edytor tekstu.

Osobiście na codzień używam raczej Emacsa (i GNU C), ale doskonale rozumiem, że nie każdy potrzebuje edytora tekstu wyposażonego w moduł do psychoanalizy }-]

Jeśli intersuje pana kurs C, to może miałby pan chęć pomóc mi scalić go bardziej z systemem Moodle?

Pozdrawiam.
In reply to Marian Rusek

Odp: Odp: Odp: kurs C wersja 0.01

by Wojciech Bojewski -
Nie znam sie na C az tak jak bym chcial... aczkolwiek scheciam bym chcial poznac lepiej, dlatego jestem zainsteresowany wszelkimi dzialaniami zwiazanymi z C (szczegolnie, ze ostatnio czesto jest mi potrzebny:) )
Schecia pomoge... w miare moich mozliwosci i umiejetnosci :-)

Pozdrawiam Wojciech Bojewski
In reply to Administrator Moodle

Odp: kurs C wersja 0.01

by Jerzy Różański -

Mam następujące uwagi dotyczące używania C, które być może pomogą również mi w implementacji i używaniu tego języka na uczelni:

1. Istnieje darmowy kompilator gcc pod Linux i jego wersja pod Windows: djgpp

2. Z tego co zauważyłem na Olimpiadzie Informatycznej używa się obydwu kompilatorów + jakiegoś programiku pod Windows, który testuje poprawność programów używanych pod Linux (szczegóły rozpracowuję)

3. Nie wszystkie programy można przenieść z Windows pod  platformę Linux, tylko ANSII C. Główny kłopot, który mi się przytrafił to używanie pamięci  ( głównie wskaźników), które w przypadku Linux kończą się wywaleniem komunikatu: naruszenie ochrony pamięci.

4. Zaletą używania kompilatorów GNU na uczelni wydaje mi się : bezpłatność, bardzo dobra dokumentacja, otwarty kod, który dobrze służy nauce studentów, bo można zobaczyć jak to jest skonstruowane (ale to wszystko sami wiecie)

5. Osobiście zdecydowałem się na kompilację przykładów na platformie Windows ze względu na popularność w domach, ale jestem zainteresowany problemem przeniesienia tych przykładów pod Linux.

Pozdrowienia, Jerzy Różański

In reply to Jerzy Różański

Odp: Odp: kurs C wersja 0.01

by Marian Rusek -
Ależ djgpp jest kompilatorem pod DOS! A tego nie można nawet nazwać systemem operacyjnym :-D

Sugerowałbym raczej używanie kompilatora C z kolekcji Minimalistic GNU for Windows. Wygodny Windowsowy instalator można ściągnąć stąd.

Oczywiście jest to kompilator w wersji command line, więc trzeba zdecydować się na edytor tekstu, który tworzy z nim zintegrowane środowisko programistyczne. Nie chcąc rozpoczynać Holly WarTM na temat edytorów, zasugerowałbym jednak Emacsa }-]. Auto-Hungry-Mode jest naprawdę fajny ;-). Zauważ jednak, że używanie Emacsa do kompilacji wymaga nauczenia studentów stuktury pliku Makefile...

Dla nie wtajemniczonych w dzieła Wielkiego Gnuciusa muszę jeszcze dodać, że kompilator gcc jest nie tylko darmowy, ale przede wszystkim wolny (jak wolność, a nie jak szybkość ;-)). Zresztą gcc wcale nie musi być darmowy, gdyż nikt nikomu nie zabrania sprzedawania go.

Pozdrawiam.

Marian

P.S. Jeśli masz kłopoty z przenoszeniem programów między Windowsami i Linuksem, to dlaczego nie używasz Cygwina? Emuluje on wygodnie środowisko Linuksa pod Windowsami (ale generowany przez jego gcc kod jest wolniejszy niż kod generowany przez gcc z MinGW).
In reply to Marian Rusek

Odp: Odp: Odp: kurs C wersja 0.01

by Jerzy Różański -

Uwagi:

1. djgpp jest w pełni 32 bitowym kompilatorem C/C++, który (jak to się mówi) mam trochę obcykany :). Niemniej jednak ściągnąłem sobie to co wskazałeś (wcześniej tego nie znałem).

2. Emacs w wersji NTEmacs (pod Windows), którego używam w dosyć prosty sposób (bez make -k) jest dla mnie moim środowiskiem programistycznym. Czy mógłbyś w skrócie wyjaśnić zalety używania Makefile w kompilacji (prawie w ogóle tego nie używam)?

3. Cygwin niczego nowego nie wnosi dla mnie, gdyż problem dotyczy różnego sposobu używania pamięci przez oba systemy Linux i Windows. Z moich obliczeń wynika, że Linux wymaga większej dyscypliny w programowaniu. Niestety, w tej chwili, nie rozumiem jeszcze dokładnie źródeł naruszania ochrony pamięci (najczęstszy błąd) przez programy w C wprost przenoszone z Windows na Linux.

J. R.

In reply to Jerzy Różański

Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Marian Rusek -
Wezwany ponownie do tablicy odpowiadam:
  • djgpp jest 32-bitowym kompilatorem, ale pod Windows NT on sam i skompilowany przez niego kod korzysta on z emulacji DOS (a fuj). W dodatku dopiero od niedawna djgpp działa dobrze pod Windows XP, na które jesteśmy obecnie skazani (Linux nie do końca widzi nasz nowy wspaniały sprzęt firmy Dell).
  • MinGW i generowany przez niego kod jest (jak to się ładnie mówi) natywny pod Windows, tzn. jest to kod wykorzystujący wyłącznie Win32 API. Dzięki temu działa IMHO lepiej pod Windows NT/2000/XP niż kod generowany przez djgpp, który był przeznaczony raczej dla DOS i gałęzi Windows nie opartej na jądrze NT.
  • W pliku Makefile możesz określić zależności między plikami Twojego projektu. Jeśli program składa się z więcej niż jednego pliku, to po dokonaniu zmian w którymś z plików kompilowany jest tylko ten plik i pliki od niego zależące. Użycie Makefile upraszcza jednak życie nawet jeśli Twój program powstaje z tylko jednego pliku w C: w pliku Makefile można zapamiętać wszystkie opcje kompilacji, katalogi z dołączanymi plikami nagłówkowymi i bibliotekami itp. A w Emacsie podstawową zaletą jest to, że po wybraniu Compile z menu Tools nie musisz wpisywać żadnych komend, tylko wciskasz po prostu klawisz enter B-).
  • Cygwin pozwala Ci "przenosić" programy z Windows do Linuksa pozostając wciąż w Windows ^-). A te Twoje programy źle alokujące pamięć chętnie zobaczę na własne oczy 8-)
In reply to Marian Rusek

Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Jerzy Różański -

Yhm, powiedział Kubuś Puchatek ( i dalej nic nie rozumiał, skazany na XP :)). Chętnie pokażę programy pod Linux, które naruszają ochronę pamięci bez jakiejkolwiek alokacji pamięci, które są przy tym bardzo proste. Czy makefile pełni rolę podobną do plików dsw (workspace) w Microsoft C++? Przyznam, że jestem pod wrażeniem naciskania tylko Enter w Emacsie :) Tablica, do której zostałeś wezwany jest o.k. :) Pozdrowienia, Jerzy.

 

In reply to Jerzy Różański

Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Wojciech Bojewski -
Czy na łamach tej dyskusii mógłby Pan umieścić jeden (ze swoich :-) )przykładów, który narusza pamięć.

Pozdrawiam -=Wojciech Bojewski=-
In reply to Wojciech Bojewski

Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Jerzy Różański -

W załaczniku fragment programu:

1. Kompilacja pod Windows (djgpp) nie zgłasza błędów

2. Kompilacja pod Linux (prywatnie debian) daje naruszenie pamięci

3. Zaremowanie np. lini z print, daje poprawny wynik bez naruszenia pamięci.

 

Pozdrawiam wszystkich zainteresowanych, Jerzy

In reply to Jerzy Różański

Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Wojciech Bojewski -
Witam... :-)

----cut here-------
int main()
{
...

int max, maxline;

Pytanie ... ile wynosi max ?? Jeśli deklarujemy globalnie to domyślnie jest to wartość 0, a jeśli lokalnie to czy także będzie 0 ???
U mnie wynosi: 1073830176

...
printf("%d\n", max);
...

/* Moim zdaniem tu jest diabeł pogrzebany :-)
int max, maxline;
char line[max];
//powinno byc int max=0, maxline=0;
*/
...

return 0;
}
----cut here-------

Pozdrawiam Wojciech Bojewski

P.S. Radze nie używac funkcji printf w powyższy sposób ponieważ wiąże się to z pewnym niebezpieczeństwem (wg manuala man 3 printf )

Code such as printf(foo); often indicates a bug, since foo may contain a % character. If foo comes from untrusted user input, it may contain %n, causing the printf call to write to memory and creating a security hole.
In reply to Wojciech Bojewski

Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Wojciech Bojewski -
nie chodzi mi o taki zapis printf("%d\n", max);
lecz o taki zapis printf("ciag znakow");
Fragment z książki "Jezyk ANSI C"
Uwaga: funkcja printf używa swojego pierwszego argumentu do określenia liczby i typów pozostałych argumentów. Jeśli nie podałeś wystarczającej liczby argumentów lub są one złego typu, to funkcja będzie zdezorientowana, a Ty otrzymasz błędne wyniki. Powinieneś więc zdawać sobie sprawe z różnicy między tymi wywołaniami:
printf(s); /* ZLE, jeżeli w s występuje % */
printf("%s", s); /*BIEZPIECZNIE */


Pozdrawiam
In reply to Wojciech Bojewski

Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Marian Rusek -
Ale w przykładzie p. Różańskiego jest wszystko OK, gdyż w ciągu znaków s nie występuje %!
In reply to Marian Rusek

Odp:-)

by Wojciech Bojewski -
Zgadza się, ale to jest tylko rada... nie trzeba sie do niej stosować. Tylko i wylacznie dobra (mam nadzieje) rada.

Pozdrawiam
In reply to Jerzy Różański

Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Marian Rusek -
Nie za bardzo rozumiem, czemu to takie dziwne V-. Twój kod nie jest zgodny z normą ANSI języka C (w definicji tablicy powinno być wyrażenie stałe, a Twoje wyrażenie nie jest stałe) i dlatego wynik jego kompilacji zależy od kompilatora (zakładając oczywiście, że kompilatory respektują normę ANSI ;-)).

Testowałem go pod Linuksem używając kompilatorów:
  • gcc 3.3.2 (Fedora Core 1)
  1. wartość zmiennej max przy wykonaniu wynosi 0
  2. program wypisuje napis "Cokolwiek", system nie zgłasza błędów

gcc 3.2 (Red Hat Linux 8.0)
  1. wartość zmiennej max przy wykonaniu wynosi 1108580344
  2. program zatrzymuje przed wywołaniem funkcji printf, system zgłasza bład naruszenia ochrony pamięci

Dlaczego to IMHO (nie) działa tak, jak (nie) działa?
  1. przy wykonaniu programu system nie zna wartości zmiennej max, więc nie wie jak dobrać wielkość zrębu stosu dla tworzonego procesu
  2. przed wykonaniem funkcji printf tworzona jest kopia jej argumentów (są przekazywane przez wartość), na zrąb stosu właśnie
  3. system przypomina sobie wtedy o tablicy line i stara się skopiować napis za nią
  4. następuję odwołanie do pamięci poza przydzielonym zrębem stosu i voila

Kompilator gcc 3.3.2 jest sprytniejszy i przezornie wyzerował zmienną max nie przydzielając wogóle pamięci dla line.

Pozdrawiam,

Marian

P.S. Oczywiście w celu wydrukowania wartości zmiennej max nie modyfikowałem kodu, tylko użyłem odpluskwiacza (gdb) i ... Emacsa }-] (aby ustawić breakpoint).

P.P.S. Nie sądzisz, że bardzo źle świadczy o jakości pakietów Debiana, że nawet kompilacja daje w tym systemie błąd ochrony pamięci? :-D
In reply to Marian Rusek

Re: Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Pawel Sulkowski -

Moim zdaniem sprawa wyglada nastepujaco:

int main()
{
  int max;
  char tab[max];
}

poniewaz max jest zmienna lokalna, jej wartosc nie jest zerowana przy przydzielaniu pamieci, wiec wartosc tej zmiennej zalezy od tego jakie smieci mamy w pamieci. (poza tym zgadzam sie z przedmowca, jakoby taki kod nie byl zgodny ze standardem ANSII C)

Segmentation fault wyskakuje poniewaz, przewaznie max ma bardzo duze wartosci (skoro sizeof(int) = 4, jest duze prawdopodobienstwo, ze ktorys z bardziej znaczacych bitow bedzie zapalony).
Skoro max jest duza liczba program nie moze zaalokowac wymaganego miejsca dla tablicy 'tab'.

Ogolnie trzeba uwazac z liczbami, czego przykladem moze byc nastepujacy kod:


#include <stdio.h>
#include <stdlib.h>

int *alokuj(size_t rozmiar)
{
        return (int *) malloc(sizeof(int) * rozmiar);
}

int main()
{

        if (! alokuj(-1))
        {
                printf("Nie udalo sie przydzielic pamieci\n");
        }
        return 0;

}

Do funkcji alokuj przesylamy wartosc -1. Zatem zmienna wartosc, ktora jest typu unsigned int przyjmnie wartosc MAX_UNSIGNEDINT - 1 czyli jak dobrze licze to 2^32 - 2 = 4 294 967 294

4 294 967 294 * sizeof(int)[zakladam ze 4] = 171 79 869 176 bajtow do zaalokowania!

co daje w duzym orzyblizeniu 16GB! Nasze komputery maja prawo sobie z tym nie poradzic ;)

Wiecej informacji 'google Ci powie'. Haslo 'integer overflow' :) Kiedys na stronie msdn.microsoft.com byl ciekawy artykul na ten temat.


Sprawdzalem, na nastepujacej konfiguracji:


[sulek@srv0001 pcp]$uname -r
2.4.23
[sulek@srv0001 pcp]$gcc -v
Reading specs from /usr/lib/gcc-lib/i386-redhat-linux/2.96/specs
gcc version 2.96 20000731 (Red Hat Linux 7.3 2.96-113)

btw. chcialem to wiadomosc przeslac w 'plain text' - niestety moodle dorzucil mi tagi HTML:(


Pozdrawiam
Pawel Sulkowski

In reply to Pawel Sulkowski

Odp: Re: Odp: Odp: Odp: Odp: Odp: Odp: Odp: Odp: kurs C wersja 0.01

by Marian Rusek -
Ale w pana przykładzie żaden błąd nie występuje! Do wywołania segmentation fault potrzebne jest coś więcej niż tylko tablica: dr Różański zaproponował użycie funkcji printf, a ja (mam nadzieję) wyjaśniłem czemu się tak dzieje ^-)

Jeśli zaś chodzi o funkcję malloc, to jest to zupełnie inna historia od omawianej tutaj.

Dobranoc |-.

P.S. O dodawaniu tagów html przez Moodle może pan poczytać tutaj.
In reply to Jerzy Różański

(Lokalnie)zawsze zmienna;

by Wojciech Bojewski -
Ostatnio testowałem czy można wartość zmiennej zadeklarowana jako stała (const int redhat=8;) zmienić.
Gdy deklaracja była globalna (niezależnie od kombinacji ze wzkaźnikami i rzutowaniem) efekt był taki sam "Naruszenie ochrony pamięci", natomiast gdy deklaracja była wewnątrz głównaj funkcji main, stałą mogłem jawnie zmienić (owszem kompilator prostestował ale zmienił wartość).

------------------------
[hador@localhost]$ gcc zmienna.c
zmienna.c: In function `main':
zmienna.c:7: warning: increment of read-only variable `redhat'
[hador@localhost]$ ./a.out
Red Hat 8
Red Hat 9
------------------------
[hador@localhost]$ gcc --version
gcc (GCC) 3.2.2 20030222 (Red Hat Linux 3.2.2-5)
------------------------
Interesowałoby mnie czy i jakie kompilatory umożliwiają takie naruszenie...

Pozdrawiam -=Wojciech Bojewski=-
In reply to Wojciech Bojewski

Odp: (Lokalnie)zawsze zmienna;

by Marian Rusek -
const jest jedynie sugestią dla kompilatora, aby wykrywał próby zmiany wartości tych zmiennych. Oczywiście kompilator może robić to jedynie podczas kompilacji. gcc ufa panu, że pan wie co robi i pozwala panu zrobić wszystko, co pan tylo zechce (o ile on umie to skompilować). Inne kompilatory nie są już tak miłe: np. Borland C++ wogóle nie kompiluje tego kodu.

Przy okazji odkrył pan istotną różnicę między zmiennymi lokalnymi (w blokach) i globalnymi (w pliku lub całym programie). Zmienne lokalne trafiają na stos (tak musi się dziać, aby można było zaimplementować rekurencję) natomiast globalne gdzie indziej (nazwijmy to zrębem danych). Na stosie nie da się sprawdzić, czy zmienna jest zmienna tylko do odczytu, natomiast na zrębie danych się da: robi to system operacyjny i pana program pada.

Polecam ściągnięcie MinGW i zobaczenie jak ładnie pana program pada pod Windows :-D

Pozdrawiam.
In reply to Administrator Moodle

Odp: kurs C wersja 0.01

by Wojciech Bojewski -
Mam takie pytanie...

//--------------------------------------
#include
int i=7;
int main()
{
int i=4;
printf("Zmienna globalna: %d\n", ::i); // error
printf("Zmienna lokalna: %d\n", i); //Zmienna lokalna: 4
return 0;
}
//--------------------------------------

w C++ aby mic dostep do zmiennaj globalnej (jesli w lokalnym zakresie wystepuje taka sama zmienna (nazwa zmiennej) uzywamy operatora zakresu :: a w jezyku C jest taka mozliwosc?

Pozdrawiam
In reply to Wojciech Bojewski

Odp: kurs C wersja 0.01

by Wojciech Bojewski -
Witam...
...zeby nie bylo, ze problem nie ma rozwiazania... oto moje...

Zrobic strukture (bez nazwy) w ktorej bedziemy deklarowac zmienne. Struktura powinna sie konczyc jedna deklaracja egzemplarza.

np.

struct
{
int  i;
char z;
} global;

taki zapis umozliwia nam dostep do zmiennych ale usuwa mozliwosc inicjowania zmiennych...

struct
{
int  i=5; //error
char z='a'; //error
} global;

niby mamy mozliwosc inicjowania struktury...

struct
{
int  i;
char z;
} global = {5, 'a'};

ale jesli wystapi w strukturze tablica np 30 znakowa to inicjowanie struktury moze byc klopotliwe...

Aby to ladnie wygladalo i funkcjonowało nienajgorzej proponuje zrobic plik naglowkowy "global.h" o zawartosci...

#IFNDEF GLOBALS_H
#define GLOBALS_H
#define GLOBALS_VAR_START struct {
#define GLOBALS_VAR_END  } _g_v_;
#define GLOBAL(a) _g_v_.a
#ENDIF

teraz w pliku zrodlowym dodajemy plik naglowkowy i mozemy uzywac zmienne globalne, o tak...

#include <stdio.h>
#include <stdlib.h>
#include "global.h"

GLOBALS_VAR_START
int  i;
char j;
GLOBALS_VAR_END

int main()
{
GLOBAL(i) = 5;
printf("Zmienna globalna (i=%d)\n", GLOBAL(i)    );
printf("Zmienna globalna (j=%d)\n", GLOBAL(j) = 8 );
system("PAUSE"); 
}

Pozdrawiam