Vraag Aanwijzer naar geheugenbuffer gieten om naar VLA te wijzen


in C geloof ik dat het volgende programma geldig is: een verwijzing naar een toegewezen geheugenbuffer naar een array als deze casten:

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

#define ARRSIZE 4

int *getPointer(int num){
    return malloc(sizeof(int) * num);
}

int main(){
    int *pointer = getPointer(ARRSIZE);
    int (*arrPointer)[ARRSIZE] = (int(*)[ARRSIZE])pointer;

    printf("%d\n", sizeof(*arrPointer) / sizeof((*arrPointer)[0]));

    return 0;
}

(deze uitgangen 4).

Is het in C99 echter veilig om dit met VLA's te doen?

    int arrSize = 4;
    int *pointer = getPointer(arrSize);
    int (*arrPointer)[arrSize] = (int(*)[arrSize])pointer;

    printf("%d\n", sizeof(*arrPointer) / sizeof((*arrPointer)[0]));

    return 0;

(ook uitgangen 4).

Is dit legitiem, volgens de C99-standaard?

Het zou heel vreemd zijn als het legitiem is, omdat dit zou betekenen dat VLA's effectief mogelijk maken dynamische type creatiebijvoorbeeld soorten van het soort type(*)[variable].


12
2018-02-15 09:51


oorsprong


antwoorden:


Ja, dit is legitiem en ja, het variabel gemodificeerd type systeem is uiterst nuttig. U kunt de natuurlijke array-syntaxis gebruiken om toegang te krijgen tot een aaneengesloten 2D-array waarvan beide dimensies pas in runtime bekend waren.

Het zou syntactische suiker kunnen worden genoemd, want er is niets wat je kunt doen met deze typen die je niet zonder zou kunnen, maar het zorgt voor een schone code (naar mijn mening).


7
2018-02-15 10:14



Ik zou zeggen dat het geldig is. De Laatste versie van de C99-standaard (aangehaald op Wikipedia) zegt in paragraaf 7.5.2 - Array declarators alinea 5: Als de grootte een expressie is die geen constante expressie van een geheel getal is: ... elke keer dat deze wordt geëvalueerd, moet deze een waarde groter dan nul hebben. De grootte van elke instantie van een array met variabele lengte verandert niet tijdens zijn levensduur.

Het zegt zelfs expliciet dat het kan worden gebruikt in een sizeof  op voorwaarde dat de maat nooit verandert : Waar een maat expression maakt deel uit van de operand van een operator sizeof en verandert de waarde van de formaatexpressie zou het resultaat van de operator niet beïnvloeden, deze is niet gespecificeerd of niet de grootte-uitdrukking wordt geëvalueerd.

Maar de standaard zegt ook dat dit alleen is toegestaan ​​in een declarator met een blokbereik of een functieprototype: Een gewone identifier (zoals gedefinieerd in 6.2.3) met een variabel gewijzigd type moet ofwel block scope en geen koppeling of functie prototype scope. Als een identificator wordt gedeclareerd om een ​​object met een statische opslagduur te zijn, mag het geen array met variabele lengte hebben.

En een voorbeeld legt later uit dat het niet kan worden gebruikt voor lidvelden, zelfs niet in een blokbereik:

...
void fvla(int m, int C[m][m]); // valid: VLA with prototype scope
void fvla(int m, int C[m][m]) // valid: adjusted to auto pointer to VLA
{
    typedef int VLA[m][m]; // valid: block scope typedef VLA
    struct tag {
        int (*y)[n]; // invalid: y not ordinary identifier
        int z[n]; // invalid: z not ordinary identifier
    };
...

2
2018-02-15 10:26