Hva er den riktige måten å klargjøre en meget stor struct?

stemmer
22

I vår kode pleide vi å ha noe sånt som dette:

   *(controller->bigstruct) = ( struct bigstruct ){ 0 };

Dette pleide å fungere bra, og da har vi oppgradert versjon av GCC og plutselig begynte å se stack overflow. Ser på forsamlingen, ble den gamle GCC-kode (2.x) i utgangspunktet gjøre dette:

memset(controller->bigstruct, 0, sizeof(struct bigstruct));

Den nye GCC (3.4.x) gjorde dette

   struct bigstruct temp = { 0 };
   controller->bigstruct = temp;

Etter gjennomgang av C99 spec, kunne jeg se hvorfor; C99 i utgangspunktet krever at anonyme strukturer finnes på stakken. Det er et godt konsept, men denne strukturen var 4 megabyte stor, og bare noen gang ment å eksistere på haugen!

Vi har tydd til å gjøre vår egen 'initialize' -funksjonen som eksplisitt setter medlemmene, men det er stygt og vedlikehold hodepine. Jeg anser ikke memset en skikkelig løsning, fordi jeg ikke kan vite at en bit-verdi på 0 er en passende null verdi for typen (flisespikkeri, jeg vet, men det er du, jeg har ikke noe imot at kompilatoren gjør det, fordi det kan vite)

Hva er riktig, eller i det minste beste, måten å klargjøre en stor struktur som dette?

Til furthur forklare hvorfor jeg tror memset er ikke en løsning: Reglene for initialisering av medlemmene ikke eksplisitt initialisert er det samme som statisk initialisering, og er som følger: - Hvis det har pekertypen, er det initialisert til en nullpeker; - Hvis det har aritmetikk type, er den klargjort for (positiv eller unsigned) null; ...

'Memset' vil sette minnet til bit-mønster null, noe som ikke nødvendigvis er det samme. Tenk deg et system som ikke bruker IEEE flyttall. Uvanlig, men understøttet av C. Representasjonen av 0,0 ikke behøver å bety all-bits null, kan det være hva som helst passende til prosessoren.

Publisert på 07/10/2008 klokken 06:32
kilden bruker
På andre språk...                            


5 svar

stemmer
21

memset er veien å gå. Du har ikke mange alternativer.

Gjør noe sånt som:

#define InitStruct(var, type) type var; memset(&var, 0, sizeof(type))

Slik at du bare trenger å:

InitStruct(st, BigStruct);

Og deretter bruke p som vanlig ...

Jeg får ikke hvordan "0" er ikke en gyldig "0" for en struct. Den eneste måte å "mass initialisere" en struct er å angi alle dens minne til en verdi; ellers ville du har å gjøre ekstra logikk for å fortelle den til å bruke en bestemt bitmønster per medlem. Den beste "generisk" bit mønster å bruke er 0.

I tillegg - dette er den samme logikken som du brukte når du gjør

*(controller->bigstruct) = *( struct bigstruct ){ 0 };

Derfor jeg ikke får uvilje mot å bruke det :)

Den første kommentaren til dette innlegget fikk meg til å gjøre noen undersøkelser før jeg ringte ham og idiot og jeg fant dette:

http://www.lysator.liu.se/c/c-faq/c-1.html

Veldig interessant; om jeg kunne stemme opp en kommentar jeg ville :)

Når det er sagt - det eneste alternativet hvis du ønsker å målrette arkaiske arkitekturer med ikke-0 nullverdier er fortsatt å gjøre manuelle initialisering til visse medlemmer.

Takket Thomas Padron-McCarthy! Jeg lærte noe nytt i dag :)

Svarte 07/10/2008 kl. 06:38
kilden bruker

stemmer
6

Hvis du ikke ønsker å bruke memset, kan du alltid erklære en statisk kopi av struct og bruk memcpy, som vil gi tilsvarende ytelse. Dette vil legge 4 Mb til programmet, men er trolig bedre enn å sette enkeltelementer.

Når det er sagt, hvis GCC brukte memset, og det var godt nok tidligere, ville jeg foreslå det er god nok nå.

Svarte 07/10/2008 kl. 06:38
kilden bruker

stemmer
5

Som andre har sagt, er memset veien å gå. Men ikke bruk memset på C ++ objekter, særlig de med virtuelle metoder. Den sizeof( foo )vil omfatte tabellen virtuelle funksjonspekere, og gjør en memset på som vil føre til alvorlige sorg.

Hvis memset ikke løser problemet av seg selv, bare gjøre en memset og deretter initial noen medlemmer som skal være ikke-null (dvs. ikke-IEEE flyt verdier).

Svarte 07/10/2008 kl. 10:54
kilden bruker

stemmer
4

Private initialisering funksjonen er ikke stygg heller en god OO måte å initialisere objekter (structs). Jeg antar at strukturen ikke er 4 MB pekere, så jeg vil anta at løsningen skal være som dette:

void init_big_struct(struct bigstruct *s)  
{  
    memset(s, 0, sizeof(struct bigstruct));  
    s->some_pointer = NULL; // Multiply this as needed  
}

Fra andre siden vår kode kjører på mer enn 20 innebygde operativsystemer og stort antall ulike Hardwares, aldri møter noen problem med bare memset av struct.

Svarte 07/10/2008 kl. 07:08
kilden bruker

stemmer
-2

hmm - først og fremst å lage en init funksjon og innstilling hvert medlem eksplisitt er den riktige tingen - det er slik konstruktører i OO språk fungerer.

og andre - er det noen som vet om et hardware som implementerer ikke IEEE flyttall? - kanskje Commodore 64 eller somethig ;-)

Svarte 07/10/2008 kl. 06:57
kilden bruker

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more