A helyi információ és az id kezelése Programozás II. Széchenyi István Egyetem, Gy r 2014. május 28.
Helyi információ Helyi információ elemei ( helyi kategóriák): ország nyelv alkalmazott karakterkódolás dátum, id, pénzügyi mennyiség, számok formátuma pénznem, stb. locale.h szimbolikus állandók, típusok, függvény prototípusok Bizonyos könyvtári rutinok a beállított helynek megfelel en m ködnek (pl. karakterláncok összehasonlítása strcoll() fv.-nyel) mások viszont nem (pl. hibaüzenetek nyelve) Alapértelmezés: C hely
Helyi információ beállítása char* setlocale(int kategoria, const char* hely) kategoria LC_ALL LC_COLLATE LC_CTYPE LC_MONETARY LC_NUMERIC LC_TIME Mire hat? Minden kategóriára. Karakterláncok lexikograkus sorrendnek megfelel alakra konvertálását végz, vagy azokat ily módon összehasonlító függvények viselkedésére. Karakterosztályozó és konverziós rutinok m ködésére, kivéve isdigit(), isxdigit(). Pénzügyi értékek formázására. A nem pénzügyi értékek (számok) formázására. Dátumot és id t formázó függvények m ködésére.
Helyi információ beállítása hely karakterlánc ált. alakja: [nyelv[_ország]][.kódlap] Pl. "English_USA.1252", "Hungarian_Hungary.1250", de OS függ! hely Hatás NULL Nem módosít semmit. "C" C helyet állít (alapértelmezés): egy bájtos karakterek, tizedespont,... "" Az operációs rendszert l lekérdezett helyet használja. Különleges kódlapok: ACP ANSI alapértelmezett kódlap OCP OEM alapértelmezett kódlap Visszatérés: aktuális beállítások értéke pl. állapot kés bbi visszaállításához vagy NULL, ha a kérés nem teljesíthet Statikus puer!
Karakterláncok összehasonlítása int strcmp(const char* s1, const char* s2) Visszatérés: <0 ha s1 < s2 0 ha s1 == s2 >0 ha s1 > s2 int strcoll(const char* s1, const char* s2) Visszatérés: mint strcmp(), de gyelembe veszi a helyi beállításokat (LC_COLLATE) Csak a C helyen egyezik a lexikograkus sorrend a karakterkészlet sorrendjével!
Karakterláncok összehasonlítása size_t strxfrm(char* cél, const char* forrás, size_t n) Átalakítja forrás -t, majd eltárolja cél címen úgy, hogy azt strcmp()-vel használva az eredmény ua. legyen, mint az strcoll()-é el zetes átalakítás nélkül. Az átalakított karakterláncnak legfeljebb az els n karakterét tárolja a C helyen: strncpy(cél, forrás, n); Visszatérés: a cél tárolásához szükséges bájtok száma '\0' nélkül ha ez n, az eredmény meghatározatlan Szükséges tárterület meghatározása: strxfrm(null, forrás, 0)+1
Karakterláncok összehasonlítása strcmp(), strcoll(), strxfrm(), 1/2 #include <stdio.h> #include <stdlib.h> #include <locale.h> #include <string.h> #include <windows.h> #define S1 "á" #define S2 "z" void hasonlit(void); int main(void) { char *regi, *mentes; SetConsoleOutputCP(1250); printf("alapértelmezett hely: %s\n", regi=setlocale(lc_all, NULL)); if(!(mentes = (char*)malloc(strlen(regi)+1))) { fprintf(stderr, "Memóriafoglalási hiba.\n"); return 1; } strcpy(mentes, regi); hasonlit(); printf("új hely: %s\n", setlocale(lc_all, "Hungarian_Hungary.1250")); hasonlit(); setlocale(lc_all, mentes); free(mentes); return 0; }
Karakterláncok összehasonlítása strcmp(), strcoll(), strxfrm(), 2/2 void hasonlit(void) { char *xfrm1, *xfrm2; size_t meret; printf("strcoll: %d\n", strcoll(s1, S2)); printf("strcmp: %d\n", strcmp(s1, S2)); meret = strxfrm(null, S1, 0)+1; if(!(xfrm1 = malloc(meret))) { fprintf(stderr, "Memóriafoglalási hiba (xfrm1)\n"); exit(1); } strxfrm(xfrm1, S1, meret); meret = strxfrm(null, S2, 0)+1; if(!(xfrm2 = malloc(meret))) { fprintf(stderr, "Memóriafoglalási hiba (xfrm2)\n"); exit(1); } strxfrm(xfrm2, S2, meret); printf("strcmp+strxfrm: %d\n", strcmp(xfrm1, xfrm2)); free(xfrm1); free(xfrm2); }
Karakterláncok összehasonlítása Kimenet Alapértelmezett hely: C strcoll: 1 strcmp: 1 strcmp+strxfrm: 1 éj hely: Hungarian_Hungary.1250 strcoll: -1 strcmp: 1 strcmp+strxfrm: -1
Karakterosztályozó és -konvertáló függvények/makrók Ide tartoznak: is...(), to...() Figyelembe veszik az LC_CTYPE helyi kategória beállítását Figyelem! int típussal dolgoznak [0x80, 0xFF] közötti karakterkódok: el jel kiterjesztés Megoldás: unsigned char használata
Karakterkonvertáló makrók int tolower(int c), int toupper(int c) #include <stdio.h> #include <locale.h> #include <ctype.h> unsigned char* nagy(unsigned char *s) { unsigned char *m = s; while(*s) *s++=toupper(*s); return m; } unsigned char* kicsi(unsigned char *s) { unsigned char *m = s; while(*s) *s++=tolower(*s); return m; } int main(void) { unsigned char s[] = "Árvízt r Tükörfúrógép"; setlocale(lc_ctype, "Hungarian_Hungary.1250"); printf("%s\n", s); printf("%s\n", nagy(s)); printf("%s\n", kicsi(s)); return 0; }
Pénzügyi és numerikus beállítások struct lconv* localeconv(void) Visszatérés: aktuális pénzügyi és numerikus beállításokat tartalmazó, statikus lconv struktúra címe Struktúrát módosítja: localeconv(), setlocale() LC_ALL, LC_NUMERIC, LC_MONETARY kategóriák esetén Közvetlenül ne módosítsuk a struktúrát! Az LC_NUMERIC kategória hatást gyakorol: karakterláncokat bels ábrázolási formára alakító fv.-ek m ködésére (pl. atof(), atoi(), atol()) formázott ki- és bemenetet kezel fv.-ekre (scanf és printf család)
Az lconv struktúra Szabványos fv. könyvtár elemei csak a decimal_point tagot használják char* típusú tagok tulajdonságai: üres karakterlánc (""): az aktuális hely nem támogatja a funkciót C hely: minden ilyen tag értéke "", kivéve decimal_point, ami "." char típusú tagok tulajdonságai: nem negatív számok CHAR_MAX érték ek: nem támogatja az aktuális hely C hely: minden ilyen tag értéke CHAR_MAX
Az lconv struktúra Struktúratag char* decimal_point char* thousands_sep char* grouping Funkció Decimális pont karakter Ezres csoportok elválasztó karaktere (decimális ponttól balra) Számjegy csoportok mérete. Az LC_NUMERIC kategóriához (nem pénzügyi mennyiségek) kapcsolódó struktúratagok A grouping lehetséges elemei: CHAR_MAX befejezi a további csoportosítást ( és a karakterláncot is) '\0' el z elem ismétlése minden további számjegyre n csoportot alkotó számjegyek száma Pl. {3, 2, CHAR_MAX} 987654321 9876,54,321 "\3" {3, 0} 987654321 987,654,321
Az lconv struktúra Struktúratag Funkció char* int_curr_symbol Nemzetközi pénznem szimbólum ISO4217 alapján, pl. "USD " char* currency_symbol Pénznem szimbólum, pl. "$" char* mon_decimal_point Decimális pont karakter char* mon_thousands_sep Számjegy csoportokat elválasztó karakter char* mon_grouping Számjegy csoportok mérete, ld. grouping char* positive_sign Pozitív el jel char* negative_sign Negatív el jel char int_frac_digits Számjegyek száma a decimális ponttól jobbra (nemzetközi formázás) char frac_digits Számjegyek száma a decimális ponttól jobbra Az LC_MONETARY kategóriához (pénzügyi mennyiségek) kapcsolódó struktúratagok
Az lconv struktúra Struktúratag Funkció char p_cs_precedes 1: pénznem szimbólum megel zi a nem negatív mennyiséget, 0: követi azt char p_sep_by_space 1: pénznem szimbólumot szóköz választja el a nem negatív mennyiségt l, 0: nincs elválasztás char n_cs_precedes 1: pénznem szimbólum megel zi a negatív mennyiséget, 0: követi azt char n_sep_by_space 1: pénznem szimbólumot szóköz választja el a negatív mennyiségt l, 0: nincs elválasztás char p_sign_posn El jel pozíciója nem negatív mennyiségeknél char n_sign_posn El jel pozíciója negatív mennyiségeknél Az LC_MONETARY kategóriához (pénzügyi mennyiségek) kapcsolódó struktúratagok
Az lconv struktúra A char p_sign_posn és char n_sign_posn tagok értelmezése 0 Mennyiség és pénznem szimbólum zárójelek között 1 Az el jel megel zi a mennyiséget és a pénznem szimbólumot 2 Az el jel követi a mennyiséget és a pénznem szimbólumot 3 Az el jel közvetlenül megel zi a pénznem szimbólumot 4 Az el jel közvetlenül követi a pénznem szimbólumot
Helyi információk hatása különféle mennyiségek formázására Az lconv struktúra kipróbálása, 1/2 #include <stdio.h> #include <stdlib.h> #include <locale.h> void helyinfo(double d) { struct lconv* plc; char puff[32]; printf("aktuális hely: %s\n", setlocale(lc_all, NULL)); plc = localeconv(); printf("decimális pont karakter: %s\n", plc->decimal_point); printf("pénznem szimbólum: %s\n", plc->currency_symbol); printf("nemzetközi pénznem szimbólum: %s\n", plc->int_curr_symbol); printf("lebeg pontos érték: %.2f\n", d); sprintf(puff, "%f", d); printf("u.a. karakterlánc formájában: %s\n", puff); printf("visszaalakítva: %.2f\n", atof(puff)); }
Helyi információk hatása különféle mennyiségek formázására Az lconv struktúra kipróbálása, 2/2 int main(void) { double ertek = 3.14; helyinfo(ertek); setlocale(lc_all, ""); helyinfo(ertek); return 0; }
Az id kezelése time() time_t difftime() double ctime() char* mktime() gmtime() localtime() struct tm* asctime() strftime()
Az id kezelése Kétféle id között kell különbséget tenni: helyi id egyezményes id (Universal Time Coordinated, UTC; korábban: Greenwich Mean Time, GMT) Típusok, struktúradeníciók, függvény prototípusok time.h A függvények statikus puereken osztoznak: id karakterlánc (char*) id struktúra (struct tm)
Az id kezelése time_t time(time_t* idomut) Az 1970.01.01 00:00:00 óta eltelt mp.-ek számát adja UTC szerint Ha az id nem határozható meg, a visszatérési érték: (time_t)-1 Az id t az idomut címen is elhelyezi, ha az nem NULL A time_t típus: typedef aritmetikai_tipus time_t; Az aritmetikai_tipus jellemz en long.
Az id kezelése double difftime(time_t ido1, time_t ido0) Visszatérés: ido1 és ido0 naptári id k különbsége, mp.-ekben A difftime() lehetséges megvalósítása #define difftime(t1,t0) (double)(t1 - t0) char* ctime(const time_t* ido) Visszatérés: a helyi id t tartalmazó, rögzített formátumú karakterlánc címe, vagy NULL, ha ido negatív. ctime(ido); asctime(localtime(ido)); Az id karakterlánc: pontosan 26 karakteres, minden mez konstans szélesség, 24 órás formátumú. Pl. "Wed Jun 30 21:49:08 1993\n"
Az id kezelése struct tm* gmtime(const time_t* ido) struct tm* localtime(const time_t* ido) tm struktúrába konvertálják az ido -t, majd ennek címével térnek vissza A visszatérési érték NULL, ha ido negatív A localtime() az id a helyi id zónára alakítja, a gmtime() ilyet nem tesz
Az id kezelése Struktúratag Funkció tm_sec Másodperc (0-59) tm_min Perc (0-59) tm_hour Óra (0-23) tm_mday Hónap napja (1-31) tm_mon Hónap (0-11, január=0) tm_year Év-1900 tm_wday A hét napja (06, vasárnap=0) tm_yday Napszám az éven belül (0365, január 1.=0) tm_isdst Pozitív: nyári id számítás, 0: téli id számítás, negatív: ismeretlen állapot A tm struktúra tagjai; mindegyik int típusú, sorrendjüket a szabvány nem rögzíti
Az id kezelése time_t mktime(struct tm* idomut) Normalizálja, teljesen kitöltötté teszi a idomut struktúrát, majd time_t-vé alakítva visszadja. Normalizálás: pl. október 40. november 9. Kitöltés: kiszámítja tm_wday és tm_yday tagok értékét a többi tag értéke alapján, meghatározza tm_isdst értékét. A tm_isdst tagot mindenképpen be kell állítani! 1 kéri a téli/nyári id számítás automatikus meghatározását. A visszatérési érték meghatározásához nem használja a tm_wday és tm_yday tagokat. Visszatérés (time_t)-1, ha az átalakítás lehetetlen (pl. 1970.01.01 00:00:00 el tti id pont)
Az id kezelése char* asctime(const struct tm* idomut) Átalakítja az idomut címezte struktúrát helyi id szerinti id karakterlánccá. Formátum: mint ctime()-nál. Nincs hibás visszatérés. size_t strftime(char* puffer, size_t maxmeret, const char* format, const struct tm* idomut) Megformázza az idomut címen lév id t format -nak megfelel en, majd az eredményt elhelyezi a maxmeret méret puffer -ben. Visszatérés: tárolt karakterek száma, vagy 0, ha nem fér el az eredmény és puffer tartalma meghatározatlan. Hasonlít printf()-re: % jelet követ formátumkódok helyére adatot helyettesít, minden mást változatlanul átmásol. M ködését befolyásolja az LC_ALL vagy LC_TIME kategóriás setlocale() hívás.
Az id kezelése Formátumkód Funkció Y 4 karakteres decimális évszám m Decimális hónapszám (01-12) B Teljes hónapnév (pl. december) d Nap a hónapon belül (01-31) A Hét napja (pl. vasárnap) H Óra (00-23) M Perc (00-59) S Másodperc (0059) % % jel c A helynek megfelel teljes id bélyeg x A helynek megfelel dátum X A helynek megfelel id Néhány alkalmazható formátumkód
Id kezelés mintapélda Dátumformátumok, naptár megjelenítés, 1/3 #include <stdio.h> #include <locale.h> #include <time.h> void naptar(int ev, int ho) { struct tm ido; int napok[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }, nap; if(ev%4==0 && ev%100!=0 ev%400==0) napok[2]++; ido.tm_year = ev-1900; ido.tm_mon = ho-1; ido.tm_mday = 1; ido.tm_hour = ido.tm_min = ido.tm_sec = 0; ido.tm_isdst = -1; mktime(&ido); if(!ido.tm_wday) ido.tm_wday=7; printf("hét Ked Sze Csü Pén Szo Vas\n"); for(nap=1; nap<ido.tm_wday; nap++) printf(" ");
Id kezelés mintapélda Dátumformátumok, naptár megjelenítés, 2/3 for(nap=1; nap<=napok[ho]; nap++) { printf("%3d ", nap); if(ido.tm_wday==7) { putchar('\n'); ido.tm_wday=1; } else ido.tm_wday++; } if(ido.tm_wday!=1) putchar('\n'); } #define MAX 64 int main(void) { time_t ido = time(null); struct tm *ptm; char puff[max]; setlocale(lc_all, ""); printf("ctime(): %s", ctime(&ido)); ptm = localtime(&ido); printf("localtime(): %4d.%02d.%02d %02d:%02d:%02d\n", ptm->tm_year+1900, ptm->tm_mon+1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec);
Id kezelés mintapélda Dátumformátumok, naptár megjelenítés, 3/3 strftime(puff, MAX, "strftime(): %x (%A) %X\n", ptm); printf(puff); naptar(2014, 4); return 0; } Kimenet ctime(): Sat Apr 19 19:41:25 2014 localtime(): 2014.04.19 19:41:25 strftime(): 2014.04.19. (szombat) 19:41:25 Hét Ked Sze Csü Pén Szo Vas 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
Az id kezelése clock_t clock(void) Visszaadja a folyamat által hozzávet legesen elhasznált processzorid t, id zít egységekben. 1 id zít egység = 1/CLOCKS_PER_SEC másodperc Ha az érték nem határozható meg, vagy nem ábrázolható, a visszatérési érték (clock_t)-1. A clock_t aritmetikai típus, többnyire long. Program adott id re történ felfüggesztése #include <time.h> void sleep(clock_t sec) { clock_t ig = sec*clocks_per_sec + clock(); while(ig > clock()); } Figyelem! foglalva várakozás (busy waiting) a processzor idejét más folyamat ( program) is használhatja