6. cvičení

Proměnné typu struktura (struct) jsou v jazyce C v paměti uloženy jednoduše jako její prvky za sebou, tzn. adresa struktury je stejná jako adresa jejího prvního prvku. Např. struct { long a; short b; } s; je uložena jako 6 bytů - 4 byty pro a, 2 pro b, přes proměnnou s se v Assembleru dostaneme k prvnímu prvku s.a.

Při práci se strukturami je potřeba brát v potaz, že pro větší efektivnost dochází ješte k tzv. zarovnání velikosti struktury (padding) na vhodný násobek 4 nebo 8. To znamená, že i když výše uvedená struktura potřebuje k uchování dat pouze 6 bytů, ve skutečnosti zabere v paměti 8 bytů. Ověřte si to vhodným použitím operátoru sizeof.

Vedle zarovnání velikosti objektů je potřeba dbát i na zarovnání jednotlivých členů struktury. Hodnoty velikosti jeden byte jsou zarovnávany na 1B, dvoubytové hodnoty na 2B, čtyřbytové hodnoty na 4B, atd. V praxi to znamená, že jednotlivé členy daného typu začínají vždy na násobku svého zarovnání, např. hodnoty typu int jsou ve struktuře uložené vždy na pozici, která je násobkem čtyř. Toto chování je nutné mít na paměti při návrhu datových struktur, protože může vést k nevhodné spotřebě paměti. Pozici, na které je daný člen uložen, je možné v jazyce C zjistit pomocí makra offsetof(struktura, clen) ze stddef.h.

#include <stdio.h>
#include <stddef.h>

struct foo {
	char a;
	short b;
	int c;
};

struct foo bar;

int main()
{
	bar.a = 0;
	bar.b = 100;
	bar.c = 200;
	printf("%i\n", offsetof(struct foo, b));
	_asm {
		mov ebx, offset bar;
		mov byte ptr [ebx], 'd';     // ulozi do bar.a = 'd'
		mov cx, [ebx + 2];  // ulozi do cx hodnotu bar.b 
		mov eax, [ebx + 4]; // ulozi do eax hodnotu bar.c
		mov dword ptr [ebx + 3], eax // !!! provede nesmyslnou operaci
	}
	return 0;
}

Úkol

  1. Zjistěte pozice jednotlivých členů ve struktuře struct foo. Prohozením členů ověřte, že se překladač chová, jak je výše popsáno. Ověřte, že pořadí členů ovlivňuje velikost struktury.
  2. Naprogramujte jednoduchou účtenkovou aplikaci.
    1. Navrhněte vhodnou strukturu, která pojme následující informace -- název položky (char *), jednotková cena (zvolte vhodnou reprezentaci), počet jednotek (unsigned int).
    2. Naprogramujte funkci receipt_add s parametry název položky, jednotková cena, počet jednotek, která přidá položku na účet.
    3. Naprogramujte funkci receipt_print, která vypíše obsah účtenky, tj. názvy položek, jednotkové ceny, počty jednotek, součin jednotkových cena * počet jednotek.
    4. Naprogramujte funkci receipt_total, která vrací celkový součet účtu.
    5. Naprogramujte funkci receipt_avg_price, která vrací průměrnou cenu položky.
    Úlohu naprogramujte nejdříve v C a pak v Assembleru. K ukládání hodnot použijte globální pole pevně dané velikosti.

Pro získání bodového hodnocení je potřeba splnit úkoly 2a, 2b, 2c a 2d (v obou jazycích).


Last update on 28. 3. 2017 18:28
Powered by Schemik.

© Petr Krajča, 2010, 2012
petr.krajca (at) upol.cz