Òèïû äàííûõ À. Ã. Ôåíñòåð, fenster@fenster.name 20 ìàðòà 2010 ã. Íà ýòîì çàíÿòèè ìû ïîãîâîðèì ïðî ðàçëè÷íûå òèïû äàííûõ â ÿçûêå C. 1 Ïðåäñòàâëåíèå ÷èñåë â êîìïüþòåðå Âñïîìíèì, êàê êîìïüþòåð õðàíèò öåëûå è âåùåñòâåííûå ÷èñëà. Äëÿ õðàíåíèÿ ÷èñåë èñïîëüçóåòñÿ äâîè÷íàÿ ñèñòåìà. Öåëûå áåççíàêîâûå ÷èñëà õðàíÿòñÿ î÷åâèäíûì îáðàçîì, öåëûå ÷èñëà ñî çíàêîì ïðåäñòàâëåíû â äîïîëíèòåëüíîì êîäå: áèòîâîå ïðåäñòàâëåíèå ÷èñëà (−k) ñîâïàäàåò ñ áèòîâûì ïðåäñòàâëåíèåì áåççíàêîâîãî ÷èñëà 2N − k, ãäå N êîëè÷åñòâî äâîè÷íûõ ðàçðÿäîâ (áèò) â äàííîì òèïå. Òàêîå ïðåäñòàâëåíèå âûáðàíî â îñíîâíîì ïî òîé ïðè÷èíå, ÷òî äîáàâëåíèå îòðèöàòåëüíûõ ÷èñåë íå èçìåíÿåò àðèôìåòè÷åñêèå îïåðàöèè (â ÷àñòíîñòè, àâòîìàòè÷åñêè âûïîëíÿåòñÿ k + (−k) = 0). Âåùåñòâåííûå ÷èñëà â êîìïüþòåðå õðàíÿòñÿ â ôîðìàòå ñ ïëàâàþùåé çàïÿòîé (ïî-àíãëèéñêè oating point, ¾ïëàâàþùàÿ òî÷êà¿, ïîñêîëüêó ó íèõ ïðèíÿòî èñïîëüçîâàòü äëÿ çàïèñè äðîáåé òî÷êó, à íå çàïÿòóþ). ×èñëî õðàíèòñÿ â âèäå ±s·2e, ãäå s ìàíòèññà (â àíãëèéñêîì ÿçûêå ïðèíÿò òåðìèí signicand), e ïîðÿäîê (exponent). Ïðåäñòàâëåíèå îáû÷íî íîðìàëèçîâàíî (1 6 s < 2). Ðàññìîòðèì ñîîòâåòñòâèå òèïîâ ÿçûêà C è ïåðå÷èñëåííûõ ìîäåëåé ïðåäñòàâëåíèÿ ÷èñåë, à òàêæå ðàçáåð¼ì îñíîâíûå íåäîñòàòêè êàæäîãî èç ñïîñîáîâ ïðåäñòàâëåíèÿ. Òèïû äàííûõ 2 Öåëûå ÷èñëà Ðàçìåð òèïà char 1 áàéò (sizeof(char) == 1). Çàìåòèì, ÷òî ñòàíäàðòû îïðåäåëÿþò áàéò êàê àäðåñóåìûé ýëåìåíò, äîñòàòî÷íûé äëÿ õðàíåíèÿ îäíîãî ñèìâîëà, ñîñòîÿùèé íå ìåíåå ÷åì èç âîñüìè áèò (êîíñòàíòà CHAR_BIT èç limits.h äà¼ò òî÷íîå çíà÷åíèå äëÿ äàííîé ðåàëèçàöèè). Ðàçìåðû îñòàëüíûõ òèïîâ ñòàíäàðòàìè â ÿâíîì âèäå íå îïðåäåëÿþòñÿ, îïðåäåëåíû ëèøü ñîîòíîøåíèÿ ìåæäó íèìè, à limits.h îïðåäåëÿåò ïðåäåëû äëÿ äàííîé ðåàëèçàöèè: INT_MAX, INT_MIN, UINT_MAX è ïðî÷èå. Ê ñòàíäàðòíûì çíàêîâûì öåëûì òèïàì îòíîñÿòñÿ signed char, short int, int, long int è long long int. Ê ñòàíäàðòíûì áåççíàêîâûì öåëûì òèïàì îòíîñÿòñÿ òå æå òèïû ñ äîáàâëåííûì ñëîâîì unsigned (unsigned char, unsigned short int è ò. ä.). ×òî êàñàåòñÿ òèïà char ðåàëèçàöèÿ âïðàâå âûáèðàòü, áóäåò îí çíàêîâûì èëè áåççíàêîâûì.  ÷àñòíîñòè, ó gcc ýòî ìîæåò áûòü çàäàíî êëþ÷îì ïðè êîìïèëÿöèè. Ðàçìåð áåççíàêîâîãî òèïà ñîâïàäàåò ñ ðàçìåðîì ñîîòâåòñòâóþùåãî çíàêîâîãî òèïà. Ñòàíäàðò ÿçûêà C íå óêàçûâàåò, êàêèì èç òð¼õ îñíîâíûõ ñïîñîáîâ (ïðÿìîé êîä, îáðàòíûé êîä, äîïîëíèòåëüíûé êîä) ïðåäñòàâëåíû îòðèöàòåëüíûå ÷èñëà.  ïðîöåññîðàõ x86 èñïîëüçóåòñÿ äîïîëíèòåëüíûé êîä (two's complement), ìû áóäåì ïðèâîäèòü ïðèìåðû èìåííî äëÿ òàêîãî ñïîñîáà õðàíåíèÿ. Èç îïðåäåëåíèÿ äîïîëíèòåëüíîãî êîäà ñëåäóåò, ÷òî ñîîòâåòñòâèå ìåæäó áåççíàêîâûìè è çíàêîâûìè òèïàìè òàêîå: unsigned char signed char 0 1 2 ... 127 128 129 ... 253 254 255 0 1 2 ... 127 −128 −127 ... −3 −2 −1 Àíàëîãè÷íî ñîîòâåòñòâóþò äðóã äðóãó áåççíàêîâûé è çíàêîâûé int è ïðî÷èå öåëûå òèïû.  ÿçûêå C íå ïðîèñõîäèò îøèáêè â ñëó÷àå âûïîëíåíèÿ ïåðåíîñà åäèíèöû â íåñóùåñòâóþùèé ñòàðøèé áèò â ñëó÷àå áåççíàêîâîãî òèïà è ïðè ïåðåïîëíåíèè è èçìåíåíèè çíàêîâîãî ðàçðÿäà çíàêîâîãî òèïà. Äëÿ öåëûõ ÷èñåë îïðåäåëåíû áèòîâûå îïåðàöèè &, |, ^ (èñêëþ÷àþùåå ¾èëè¿),~ è áèòîâûå ñäâèãè <<, >>. Âàæíî ïîíèìàòü, ÷òî &, |, ~ îòëè÷àþòñÿ îò ëîãè÷åñêèõ îïåðàöèé &&, || è !: íàïðèìåð, 7 & 8 == 0, íî 7 && 8 == 1. Áèòîâûå îïåðàöèè ìîæíî èñïîëüçîâàòü äëÿ óñòàíîâêè íóëÿ èëè åäè2 Òèïû äàííûõ íèöû â îïðåäåë¼ííûé áèò ÷èñëà. Íàïðèìåð, äëÿ óñòàíîâêè 1 â áèò k ÷èñëà a ìîæíî èñïîëüçîâàòü a |= (1 << k); äëÿ óñòàíîâêè òóäà íóëÿ ïîõîæóþ îïåðàöèþ a &= ~(1 << k); à äëÿ ïðîâåðêè çíà÷åíèÿ k-ãî áèòà ÷èñëà a ìîæíî ñðàâíèòü ñ íóë¼ì ÷èñëî (a >> k) & 1 Âñåãäà áåðèòå îïåðàöèè ñäâèãà â ñêîáêè! Ïðèîðèòåò îïåðàöèè ñäâèãà ìåíüøå, ÷åì îïåðàöèè ñëîæåíèÿ, ïîýòîìó a << b + c ñîîòâåòñòâóåò a << (b + c), ÷òî â áîëüøèíñòâå ñëó÷àåâ íå ÿâëÿåòñÿ òåì, ÷òî âû îæèäàåòå. Áèòîâûå îïåðàöèè òàêæå èñïîëüçóþòñÿ äëÿ óñòàíîâêè è ñíÿòèÿ ôëàãîâ êîíñòàíò, îáû÷íî ðàâíûõ ñòåïåíÿì äâîéêè: 1, 2, 4, 8, . . . Ýòî äà¼ò âîçìîæíîñòü õðàíèòü â îäíîé ïåðåìåííîé òèïà unsigned int çíà÷åíèÿ 32 ðàçëè÷íûõ ôëàãîâ. Íàïðèìåð, â óñëîâèÿõ òîòàëüíîé íåõâàòêè ïàìÿòè â 32 áèòàõ ìîæíî ñîõðàíèòü èíôîðìàöèþ î 32 ñäàííûõ (èëè íåñäàííûõ) ýêçàìåíàõ ñòóäåíòà: #define IS_CALCULUS_PASSED 1 #define IS_ALGEBRA_PASSED 2 #define IS_PROGRAMMING_PASSED 4 ... int student_result = 0; /* ñäàëè ïðîãðàììèðîâàíèå */ student_result |= IS_PROGRAMMING_PASSED; /* ñäàëè ëè àëãåáðó? */ if (student_result & IS_ALGEBRA_PASSED) ... 3 Âåùåñòâåííûå ÷èñëà Ñòàíäàðò íå îïðåäåëÿåò òî÷íîãî ñïîñîáà õðàíåíèÿ âåùåñòâåííûõ ÷èñåë. Íàèáîëåå ÷àñòî óïîòðåáëÿåòñÿ ôîðìàò ÷èñåë ñ ïëàâàþùåé çàïÿòîé, îïèñàííûé â ñòàíäàðòå IEEE 754. Ïðè âû÷èñëåíèè âûðàæåíèé ñ âåùåñòâåííûìè ÷èñëàìè âîçìîæíû ïîòåðè òî÷íîñòè, î êîòîðûõ âàì ïîäðîáíî ðàññêàçûâàëè íà ëåêöèÿõ ïî ïðåäñòàâëåíèþ äàííûõ.  êà÷åñòâå ïðèìåðà çàìåòèì, ÷òî öèêë 3 Òèïû äàííûõ float a = 1.0; while (a != 0.0) a /= 2.0; ñäåëàåò âïîëíå îïðåäåë¼ííîå êîíå÷íîå ÷èñëî èòåðàöèé, à öèêë float a; for (a = 0.0; a != 1.0; a += 0.1) ; áóäåò áåñêîíå÷íûì. 4 Ñòðóêòóðû è îáúåäèíåíèÿ Ïåðå÷èñëþ îñíîâíûå ôàêòû î ñòðóêòóðàõ, êîòîðûå ìîãóò âûçâàòü çàòðóäíåíèå. Âî-ïåðâûõ, èìÿ ñòðóêòóðû íå ÿâëÿåòñÿ èìåíåì òèïà â C: îáúÿâèâ struct s, ìîæíî çàâåñòè ïåðåìåííóþ òèïà struct s, íî íå òèïà s (â îòëè÷èå îò C++). Âïîëíå äîïóñòèìû àíîíèìíûå ñòðóêòóðû.  ñëåäóþùåì ïðèìåðå äâå ñòðóêòóðû ïî ñóòè îäèíàêîâû, íî ïðèñâàèâàíèå ìåæäó íèìè íåâîçìîæíî: struct { int a, b; } a; struct s { int a, b; } b; Êàê âèäíî èç ïðåäûäóùåãî ïðèìåðà, ïðè îïðåäåëåíèè ñòðóêòóðû ìîæíî ñðàçó îïðåäåëèòü ïåðåìåííóþ òàêîãî òèïà. Ïðè õðàíåíèè ñòðóêòóð âàæíî ïîíèìàòü, ÷òî ðàçìåð ñòðóêòóðû ìîæåò áûòü áîëüøå, ÷åì ñóììàðíûé ðàçìåð å¼ ýëåìåíòîâ: ýëåìåíòû ñòðóêòóðû âûðàâíèâàþòñÿ ïî îïðåäåë¼ííûì ïðàâèëàì. Íàïðèìåð, ñòðóêòóðà struct { int a; char c; int b; }; 4 Òèïû äàííûõ îáû÷íî áóäåò çàíèìàòü 12 áàéò (ìåæäó tt char c è int b áóäóò âñòàâëåíû òðè äîïîëíèòåëüíûõ áàéòà âûðàâíèâàíèÿ). Áàéòû âûðàâíèâàíèÿ ìîãóò áûòü òàêæå äîáàâëåíû â êîíåö ñòðóêòóðû, íî íå â íà÷àëî: àäðåñ ïåðâîãî ýëåìåíòà ñòðóêòóðû âñåãäà ñîâïàäàåò ñ àäðåñîì ñàìîé ñòðóêòóðû. Ðàçëè÷íûå ñïîñîáû âûðàâíèâàíèÿ ìîãóò ïðèâåñòè ê ïðîáëåìàì ïðè ÷òåíèè ñòðóêòóð, ðàíåå çàïèñàííûõ â ôàéë íà êîìïüþòåðå ñ äðóãîé ÎÑ èëè àðõèòåêòóðîé. Äëÿ îáðàùåíèÿ ê ýëåìåíòó ñòðóêòóðû èñïîëüçóåòñÿ òî÷êà, äëÿ îáðàùåíèÿ ê ýëåìåíòó ñòðóêòóðû ÷åðåç àäðåñ ñòðóêòóðû èñïîëüçóåòñÿ ¾ñòðåëî÷êà¿ ->. Âîîáùå ãîâîðÿ, â C çàïèñü p->a ÿâëÿåòñÿ áîëåå êðàòêîé çàïèñüþ äëÿ (*p)->a (ñêîáêè âàæíû: ýòî íå òî æå ñàìîå, ÷òî *p->a). Ñóùåñòâóåò òàêæå îñîáûé âèä ýëåìåíòîâ ñòðóêòóðû: áèòîâûå ïîëÿ, äëÿ êîòîðûõ óêàçûâàåòñÿ òî÷íîå êîëè÷åñòâî áèò, âûäåëåííûõ ïîä ýòî ïîëå. Íàïðèìåð, òàêàÿ ñòðóêòóðà òî÷íî ñîîòâåòñòâóåò òèïó float â ñòàíäàðòå IEEE 754: struct float { unsigned int significand: 23; unsigned int exponent: 8; unsigned int sign: 1; }; Áèòîâûå ïîëÿ ïîçâîëÿþò ðåàëèçîâàòü ôëàãè áåç îáúÿâëåíèÿ áîëüøîãî êîëè÷åñòâà ìàêðîñîâ (#define). Ïðèìåð ïðî ýêçàìåíû ìîæåò áûòü ïåðåïèñàí òàê: struct exam_list { unsigned int IS_CALCULUS_PASSED: 1; unsigned int IS_ALGEBRA_PASSED: 1; unsigned int IS_PROGRAMMING_PASSED: 1; ... }; struct exam_list student_result; student_result.IS_PROGRAMMING_PASSED = 1; Âñå ÷ëåíû îáúåäèíåíèÿ union ðàçìåùàþòñÿ â ïàìÿòè, íà÷èíàÿ ñ îäíîãî è òîãî æå àäðåñà. Îáúåäèíåíèÿ ïîçâîëÿþò ýêîíîìèòü ïàìÿòü, åñëè â îäíèõ è òåõ æå ïåðåìåííûõ ìîæåò ïîíàäîáèòüñÿ õðàíèòü çíà÷åíèÿ ðàçíûõ òèïîâ, è ðàçáèðàòü âíóòðåííþþ ñòðóêòóðó òèïîâ. Íàïðèìåð, ìîæíî çàïèñàòü 5 Òèïû äàííûõ union Float { struct float sf; float f; } u; è, ïðèñâîèâ äëÿ ïðèìåðà u.f = 1.0, ñìîòðåòü íà u.sf.significand, è u.sf.sign. Æåëàþùèå ìîãóò òàêèì îáðàçîì èçó÷èòü, êàê íà ñàìîì äåëå ïðåäñòàâëÿþòñÿ âåùåñòâåííûå ÷èñëà â ñòàíäàðòå IEEE 754. u.sf.exponent 5 Ïåðå÷èñëåíèÿ Ïåðå÷èñëåíèÿ enum èñïîëüçóþòñÿ, åñëè íóæíî ñîçäàòü òèï, ñîñòîÿùèé èç çàðàíåå îïðåäåë¼ííûõ êîíñòàíòíûõ çíà÷åíèé: enum suite { SPADE, HEART, DIAMOND, CLUB }; Çíà÷åíèÿì ìîæíî òàêæå óêàçûâàòü ñîîòâåòñòâóþùèå ÷èñëîâûå çíà÷åíèÿ.  ÿçûêå C êîíñòàíòû ïåðå÷èñëåíèÿ èìåþò ãëîáàëüíóþ îáëàñòü âèäèìîñòè, ïîýòîìó èñïîëüçîâàíèå èõ íå î÷åíü óäîáíî (ýòà ïðîáëåìà ðåøåíà â Ñ++ ââåäåíèåì ïðîñòðàíñòâ èì¼í). 6