GNU/Linux >> Znalost Linux >  >> Linux

Co vrátí malloc(0)?

Jiní odpověděli jak malloc(0) funguje. Odpovím na jednu z vašich otázek, která ještě nebyla zodpovězena (myslím). Otázka se týká realloc(malloc(0), 0) :

Co znamená malloc(0) vrátit se? Byla by odpověď stejná pro realloc(malloc(0),0) ?

Norma říká toto o realloc(ptr, size) :

  • pokud ptr je NULL , chová se jako malloc(size) ,
  • jinak (ptr není NULL ), uvolní starý ukazatel objektu na ptr a vrátí ukazatel na novou přidělenou vyrovnávací paměť. Ale pokud size je 0, C89 říká, že efekt je ekvivalentní free(ptr) . Zajímavé je, že toto prohlášení nemohu najít v návrhu C99 (n1256 nebo n1336). V C89 by jediná rozumná hodnota, která by se v tomto případě vrátila, byla NULL .

Takže existují dva případy:

  • malloc(0) vrátí NULL na implementaci. Potom vaše realloc() volání je ekvivalentní realloc(NULL, 0) . To je ekvivalentní malloc(0) shora (a to je NULL v tomto případě).
  • malloc(0) vrátí non-NULL . Potom je volání ekvivalentní free(malloc(0)) . V tomto případě malloc(0) a realloc(malloc(0), 0) nejsou ekvivalentní.

Všimněte si, že zde je zajímavý případ:ve druhém případě, kdy malloc(0) vrátí non-NULL v případě úspěchu může stále vrátit NULL indikovat selhání. Výsledkem bude volání jako:realloc(NULL, 0) , což by bylo ekvivalentní malloc(0) , který může nebo nemusí vrátit NULL .

Nejsem si jistý, zda je vynechání v C99 nedopatřením, nebo to znamená, že v C99 realloc(ptr, 0) pro jiné než NULL ptr není ekvivalentní free(ptr) . Právě jsem to zkusil s gcc -std=c99 a výše uvedené je ekvivalentní free(ptr) .

Upravit :Myslím, že chápu, v čem je váš zmatek:

Podívejme se na úryvek z vašeho příkladu kódu:

ptr = malloc(0);
if (ptr == realloc(ptr, 1024))

Výše uvedené není totéž jako malloc(0) == realloc(malloc(0), 1024) . Ve druhém malloc() volání je provedeno dvakrát, zatímco v prvním předáváte dříve přidělený ukazatel na realloc() .

Nejprve analyzujeme první kód. Za předpokladu malloc(0) nevrací NULL v případě úspěchu ptr má platnou hodnotu. Když uděláte realloc(ptr, 1024) , realloc() v podstatě vám dává nový buffer, který má velikost 1024 a ptr stane neplatným. Vyhovující implementace může vrátit stejnou adresu, jako je ta již v ptr . Takže vaše if podmínka se může vrátit jako true. (Všimněte si však hodnoty ptr po realloc(ptr, 1024) může být nedefinované chování.)

Nyní otázka, kterou si kladete:malloc(0) == realloc(malloc(0), 1024) . V tomto případě předpokládejme, že obě malloc(0) na LHS a RHS vrací non-NULL . Pak je zaručeno, že se budou lišit. Také vrácená hodnota z malloc() na LHS nebyl free() d ještě, takže jakýkoli jiný malloc() , calloc() nebo realloc() nemusí tuto hodnotu vrátit. To znamená, že pokud jste svou podmínku napsali jako:

if (malloc(0) == realloc(malloc(0), 1024)
    puts("possible");

neuvidíte possible na výstupu (pokud oba malloc() a realloc() selže a vrátí NULL ).

#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    void *p1;
    void *p2;

    p1 = malloc(0);
    p2 = realloc(p1, 1024);
    if (p1 == p2)
        puts("possible, OK");

    /* Ignore the memory leaks */
    if (malloc(0) == realloc(malloc(0), 1024))
        puts("shouldn't happen, something is wrong");
    return 0;
}

V OS X můj kód při spuštění nic nevypisoval. V systému Linux tiskne possible, OK .


malloc(0) je Implementace definována pokud jde o C99.

Od C99 [Oddíl 7.20.3]

Pořadí a spojitost úložiště přiděleného postupnými voláními funkcí calloc, malloc a realloc není specifikováno . Ukazatel vrácený, pokud je alokace úspěšná, je vhodně zarovnán tak, aby mohl být přiřazen k ukazateli na jakýkoli typ objektu a poté použit pro přístup k takovému objektu nebo poli takových objektů v přiděleném prostoru (dokud není prostor explicitně uvolněn). Životnost alokovaného objektu se prodlužuje od alokace do dealokace. Každé takové přidělení poskytne ukazatel na objekt disjunktní od jakéhokoli jiného objektu. Ukazatel vrátil body na začátek (nejnižší byteaddress) přiděleného prostoru. Pokud prostor nelze přidělit, je vrácen nulový ukazatel. Pokud je velikost požadovaného prostoru nula, je chování definováno implementací :buď je vrácen nulový ukazatel, nebo se chová, jako by velikost byla nějaká nenulová hodnota, kromě toho, že vrácený ukazatel nebude použit pro přístup k objektu.


V C89 je malloc(0) závislý na implementaci - nevím, jestli to C99 opravil nebo ne. V C++ pomocí:

char * p = new char[0];

je dobře definován – získáte platný, nenulový ukazatel. Samozřejmě nemůžete použít ukazatel pro přístup k tomu, na co ukazuje, aniž byste vyvolali nedefinované chování.

Pokud jde o to, proč to existuje, je to vhodné pro některé algoritmy a znamená to, že nemusíte zasypávat kód testy na nulové hodnoty.


Linux
  1. Co znamená „–“ (dvojitá pomlčka)?

  2. Co dělá ?

  3. Co dělá Exec 3?

  1. Co Libgl_always_indirect=1 ve skutečnosti dělá?

  2. Co vrátí příkaz Ls -al .*?

  3. Co znamená 'cd -'?

  1. Co dělá „lc_all=c“?

  2. Jaký chybový kód vrací proces, který segfaults?

  3. Co je výstupem pwd?