c + + - Kræver standarden, at objekter i automatisk lagring har den korrekte justering for enhver type (fx som malloc gør)?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg er nysgerrig om, at tildeling af en buffer på stakken er nødvendig for at have korrekt justering for enhver type, ligner hvordan malloc virker, eller hvis jeg ville blive tvunget til at bruge noget som std::aligned\_storage.


Overvej følgende blok kode:


typedef enum \_KEY\_VALUE\_INFORMATION\_CLASS {
    KeyValueBasicInformation            = 0,
    // Others
} KEY\_VALUE\_INFORMATION\_CLASS;

typedef struct \_KEY\_VALUE\_BASIC\_INFORMATION {
    ULONG TitleIndex;
    ULONG Type;
    ULONG NameLength;
    WCHAR Name[1];
} KEY\_VALUE\_BASIC\_INFORMATION, *PKEY\_VALUE\_BASIC\_INFORMATION;

std::vector<std::wstring> RegistryKey::EnumerateValueNames() const
{
    std::vector<std::wstring> result;
    ULONG index = 0;
    const ULONG valueNameStructSize = 16384 * sizeof(wchar\_t) +
        sizeof(KEY\_VALUE\_BASIC\_INFORMATION);

    // Stack buffer here
    unsigned char buff[valueNameStructSize];
    // Casted here
    KEY\_VALUE\_BASIC\_INFORMATION const* basicValueInformation =
        reinterpret\_cast<KEY\_VALUE\_BASIC\_INFORMATION const*>(buff);
    for(;;)
    {
        ULONG resultLength;
        NTSTATUS errorCheck = PNtEnumerateValueKeyFunc(
            hKey\_,
            index++,
            KeyValueBasicInformation,
            buff,
            valueNameStructSize,
            &resultLength);
        if (NT\_SUCCESS(errorCheck))
        {
            result.emplace\_back(std::wstring(basicValueInformation->Name,
                basicValueInformation->NameLength / sizeof(wchar\_t)));
        }
        else if (errorCheck == STATUS\_NO\_MORE\_ENTRIES)
        {
            break;
        }
        else
        {
            Win32Exception::ThrowFromNtError(errorCheck);
        }
    }
    return result;
}


Bemærk, hvordan værdien buff er en tegnbuffer på stakken, der er dimensioneret til at holde en given maksimal mængde data. Jeg er imidlertid bekymret over, at det stød, der kræves for at fortolke bufferen som en streng, kan medføre en justeringsfejl, hvis denne kode skulle overføres til en anden (f.eks. ARM eller IA64) platform.


EDIT: Hvis nogen er nysgerrig, redigerer jeg dette med hensyn til std::aligned\_storage og std::alignment\_of:


std::vector<std::wstring> RegistryKey::EnumerateValueNames() const
{
    std::vector<std::wstring> result;
    ULONG index = 0;
    const ULONG valueNameStructSize = 16384 * sizeof(wchar\_t) +
        sizeof(KEY\_VALUE\_BASIC\_INFORMATION);
    std::aligned\_storage<valueNameStructSize,
        std::alignment\_of<KEY\_VALUE\_BASIC\_INFORMATION>::value>::type buff;
    auto basicValueInformation =
        reinterpret\_cast<KEY\_VALUE\_BASIC\_INFORMATION*>(&buff);
    for(;;)
    {
        ULONG resultLength;
        NTSTATUS errorCheck = PNtEnumerateValueKeyFunc(
            hKey\_,
            index++,
            KeyValueBasicInformation,
            basicValueInformation,
            valueNameStructSize,
            &resultLength);
        if (NT\_SUCCESS(errorCheck))
        {
            result.emplace\_back(std::wstring(basicValueInformation->Name,
                basicValueInformation->NameLength / sizeof(wchar\_t)));
        }
        else if (errorCheck == STATUS\_NO\_MORE\_ENTRIES)
        {
            break;
        }
        else
        {
            Win32Exception::ThrowFromNtError(errorCheck);
        }
    }
    return std::move(result);
}

Bedste reference


Standarden stiller ingen krav til justering af automatiske variabler (eller variabler med statisk lagring for den sags skyld), bortset fra at kompilatoren skal sørge for at få adgang til dem.



  • C ++ 03 3.9/5 Typer




  Objekttyper har tilpasningskrav (3.9.1, 3.9.2). Det
  Justering af en komplet objekttype er en implementeringsdefineret
  heltal værdi repræsenterer et antal byte; et objekt er tildelt
  på en adresse, der opfylder justeringskravene for dens objekttype



Bemærk: 'objekttype' betyder her en type, der ikke er en funktion, reference eller tomtype (dvs. den gælder for unsigned char).


En måde at få en justeret buffer på kan være at erklære buff som sådan:


KEY\_VALUE\_BASIC\_INFORMATION buff[valueNameStructSize/sizeof(KEY\_VALUE\_BASIC\_INFORMATION) + 1];


Og du vil kunne slippe af med reinterpret\_cast<> for at starte.