Permalänk
Medlem

[C] Några frågor om malloc()

Är beteendet för denna kod väldefinerad och säker?

/* Exempel 1 */ int *x = malloc(1); *x = INT_MAX; /* Exempel 2 */ struct foo { int a; int b; float c; }; struct foo *f = malloc(1); f->a = 42; f->b = 12; f->c = 3.14f;

Som jag fattat det så garanterar malloc() att den retunerar minne som är "ok" att användas (så länge det inte är NULL), har sökt runt lite men kan inte riktigt få rätsida på det hela.

I exempel 1 kommer alltså malloc() garantera att jag får minst 4 bytes?
Och i det andra att jag får 12 bytes (om ints och floats är 4 bytes).
Är det alltså onödigt att ange sizeof(foo) om man bara vill ha minne för ett "objekt"?

Permalänk
Glömsk

malloc kan returnera NULL om det är något fel, exempelvis om minnet är slut.

Vidare så är första parametern till malloc storleken i _bytes_. Vad du vill göra i första exemplet är alltså:

int *x = malloc(sizeof(int));
if (x == NULL)
// felhantering

Samma gäller för andra exemplet.

Visa signatur

...man is not free unless government is limited. There's a clear cause and effect here that is as neat and predictable as a law of physics: As government expands, liberty contracts.

Permalänk
Medlem

Jo, jag vet att man specificerar antal bytes, jag är mest lite nyfiken på vad some händer "under the hood".

Exempel 2 som jag skrev fungerade när jag körde den, jag testade även denna kod och det funkade:

struct foo { char a[1024]; int b; float c; }; struct foo *f = malloc(1); strcpy(f->a, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"); f->b = 42; f->c = 3.14f; printf("%s\n", f->a); printf("%d\n", f->b); printf("%.2f\n", f->c);

Är det bara tur att det råkar funka?

Permalänk
Medlem

Jag tror att det finns en minsta blockstorlek som malloc kan ge en. Hur stor denna är beror nog på plattform och/eller kompilator. Så även om man vill allokera 1 byte så kan man få ett block om 8 eller 16 byte.

I ditt senaste exempel känns det som att du mest har tur. Det kan omöjligt vara väldefinierat beteende? Men jag är långtifrån någon auktoritet på C, så vad vet jag...

Permalänk

Re: [C] Några frågor om malloc()

Citat:

Ursprungligen inskrivet av dazen
Är beteendet för denna kod väldefinerad och säker?

/* Exempel 1 */ int *x = malloc(1); *x = INT_MAX; /* Exempel 2 */ struct foo { int a; int b; float c; }; struct foo *f = malloc(1); f->a = 42; f->b = 12; f->c = 3.14f;

Som jag fattat det så garanterar malloc() att den retunerar minne som är "ok" att användas (så länge det inte är NULL), har sökt runt lite men kan inte riktigt få rätsida på det hela.

I exempel 1 kommer alltså malloc() garantera att jag får minst 4 bytes?
Och i det andra att jag får 12 bytes (om ints och floats är 4 bytes).
Är det alltså onödigt att ange sizeof(foo) om man bara vill ha minne för ett "objekt"?

Det är bara (o)tur att det fungerar. Om du bara anger ett heltal så kommer malloc att tolka det som char-storlek. För att allokera minne med en godtycklig datatyp kan du skriva:
TYP var = malloc(sizeof(TYP));
I ditt exempel blir det
struct foo *f = malloc(sizeof(struct foo)));

Vill man vara ännu lurigare kan man även skriva:
struct foo *f = malloc(sizeof(*f));

Visa signatur

"I cannot. Yet I must. How do you calculate that? At what point on the graph do 'must' and 'cannot' meet? Yet I must. But I cannot."

Permalänk
Hedersmedlem

Fel ett: Du kontrollerar inte att du får tillbaka en NULLpekare från malloc. Minnet som malloc ger får du behålla tills det att processen avslutas. Men du är ju inte garanterad att få minnet alls.

Fel två: Du begär 1 byte men arbetar med som om det är fler bytes. Med otur kan du skriva över något annat (och det är det farliga med minnespekare som man själv kan ändra). Du kan inte ens veta hur många byte en 'int' tar upp, det är implementationsspecifikt (vilken kompilator och arkitektur du kör).

Beroende på arkitektur kan alignment och padding i minnet vara olika (orkar inte tänka riktigt på den här snutten) så hur mycket strukturen verkligen tar upp behöver inte vara samma som varje fält i den. Alltså gör du bäst i att göra sizeof. Och det är ingen funktion utan en operator, det beräknas vad värdet ska vara vid kompilationen och infogas i maskinkoden. Det blir alltså inget extra "overhead" vid körning gentemot om du själv räknar på hur mycket minne som behövs.

Visa signatur

Forumregler | Feedbackforumet | Något som behöver modereras? Tryck på Anmäl inlägget och ge en anledning, någon moderator kommer granska inlägget och göra (egen) bedömning
"Fate. Protects fools, little children and ships named Enterprise." - Riker - ST:TNG

Permalänk
Medlem

Ok, jag tror jag börjat fatta lite nu, tack för svaren.

Anledningen att jag började fundera på detta var att jag kollade lite på hur man implementerar generics i C, och alla void-pekare, casts hit och dit fick mitt huvud att spinna, så jag ville gå lite djupare och se vad som faktiskt händer