c - Brug af offsetof med enum kompilerer ikke i Visual Studio 2015

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg har følgende kodestykke, der kompilerer fint i Visual Studio 2013, men ikke i Visual Studio 2015.
På VS2015 får jeg fejlen 'fejl C2057: forventet konstant ekspression'


#include <stddef.h>    

struct temp {
    int a;
    char b;
};

int main() {
    enum {TEST = (offsetof(struct temp, a)? 1 : 2)};
    return 0;
}


Jeg kompilerer det ved hjælp af følgende kommando:
cl -nologo -FS-MD-EHsc-Od-D\_DEBUG-Zi-c test.c


Jeg kiggede på stddef.h-overskriften, og det ser ud til, at offsetof makroen er ændret i VS 2015.
Dette stykke kode kompilerer fint, når jeg kompilerer det ved hjælp af CPP-flag:
cl -nologo -FS-MD-EHsc-Od-D\_DEBUG -Zi-c test.c -TP


Jeg undrer mig over, hvordan kan jeg få dette stykke kode til at fungere i Visual Studio 2015. Tak!

Bedste reference



  Jeg får fejlen 'fejl C2057: forventet konstant ekspression'



VS ser ud til at være i overensstemmelse hermed. I det mindste anvender det en ukonventionel fortolkning af reglerne for heltalskonstant udtryk. MS har aldrig hævdet, at dens C-implementering er i overensstemmelse med nogen version af standarden - og det vides ikke at gøre - men fordi VS2013 gjorde det anderledes, tænkte jeg på VS2015's adfærd en fejl.


Klagen vedrører formodentlig initialisatoren for en konstant TEST. C kræver værdien at have formen af ​​et 'heltalskonstant udtryk', og en ternær operation kan absolut være et heltalskonstant udtryk, hvis dets operander er egnede. Jeg antager, at MSVC afviser koden på grund af brugen af ​​makroen offsetof(), men standarden angiver specifikt, at selve makroen udvider til et heltalskonstant udtryk (linket er et C2011-udkast, men alle tidligere udgivelser af standarden har sagt dette). [14] [15]


Ud over de generelle krav til konstante udtryk:



  Konstante udtryk må ikke indeholde opgave, stigning,
  reduktion, funktionsopkald eller kommaselskaber, undtagen når de er
  indeholdt i en subekspression, der ikke evalueres.

  
  Hvert konstant udtryk skal vurderes til en konstant, der er i
  række repræsentative værdier for sin type.



, heltal konstant udtryk er underlagt disse begrænsninger:



  Et heltalskonstant udtryk skal have heltalstype og skal
  kun har operander, der er heltalskonstanter, opregningskonstanter,
  karakterkonstanter, størrelse af udtryk, hvis resultater er heltal
  konstanter, \_Alignof udtryk, og flydende konstanter, der er
  umiddelbare operander af kaster. Cast operatører i en heltalskonstant
  udtryk skal kun konvertere aritmetiske typer til heltalstyper,
  undtagen som en del af en operand til sizeof eller \_Alignof operatøren.



Den eneste måde jeg kan analysere alt på for at udelukke din kode er at skelne mellem 'heltalskonstant' og 'heltalskonstant udtryk ' for de tilladte operander for et heltalskonstant udtryk. Jeg tror imidlertid ikke, at det er meningen med standarden, og jeg er uvidende om enhver implementering, der tager denne fortolkning - til min videns viden, selv MSVC selv tager ikke denne fortolkning i andre sammenhænge.


Hvad angår dit faktiske spørgsmål,



  Jeg undrer mig over, hvordan kan jeg få dette stykke kode til at fungere i Visual Studio 2015.



, medmindre der er nogen mulighed for, at definitionen af ​​struct temp varierer, vurderer jeg det hele ternære udtryk manuelt. Forskydningen af ​​det første medlem af en struktur skal være 0, så jeg erstatter din kode med


enum {TEST = 2};


Alternativt foreslår @HansPassant i bemærkninger denne løsning:


enum { TEST = (offsetof(struct temp, a) != 0) ? 1 : 2 };


Hvis det ikke virker for dig, er den bedste løsning, der er tilgængelig, sandsynligvis at bruge en anden (version af) kompilatoren.

Andre referencer 1


Kort svar: Det ser ud til, at VS2015 compiler er forkert.


Fra standarden:



  7,193 '

  
  Makroerne er
     ...


offsetof(type, member-designator)

  
  som udvider til et heltalskonstant udtryk



og



  6.6p3 (begrænsninger for konstante udtryk): Konstante udtryk må ikke indeholde opgave, inkrement, dekrement, funktionsopkald eller kommaoperatører, undtagen ...



Fra begge citater følger, at udtrykket ovenfor er et konstant udtryk, og enhver kompliant skal derfor acceptere den, hvor der kræves et konstant udtryk, herunder værdien af ​​en enum konstant .


Men MSVC hævder ikke at være i overensstemmelse med C-standarden. Faktisk er det ikke engang i overensstemmelse med den 18 årige tidligere version af standarden (C99). Det kan således ikke understøtte offsetof.


Hvis det virker i C ++, er det ikke noget, der bevis det er et andet sprog.





Tilføjelse:



Jeg antager, at fejlen stammer fra offsetof. En årsag til denne fejlmeddelelse ville dukke op er, at makroen ikke er defineret under kompilering. En C90 compiler vil antage, at det er en funktion (ingen prototype, implicit deklaration) defineret i en anden kompileringsenhed. Det ville faktisk gøre udtrykket ikke-konstant for at have et funktionskald (se 6.6p3 ovenfor). Jeg tror ikke, det er den betingede operatør.


Opdatering:



Ifølge denne kommentar fra @HansPassant er det en fejl i makroen i VS2015. En løsning er at eksplicit sammenligne resultatet af makroen:


(offsetof(struct temp, a) != 0) ? 1 : 2


Tilføjet af Weather Vane. Dette er MSVC 2015-definitionen fra stddef.h


// Define offsetof macro
#if defined(\_MSC\_VER) && !defined(\_CRT\_USE\_BUILTIN\_OFFSETOF)
    #ifdef \_\_cplusplus
        #define offsetof(s,m) ((size\_t)&reinterpret\_cast<char const volatile&>((((s*)0)->m)))
    #else
        #define offsetof(s,m) ((size\_t)&(((s*)0)->m))
    #endif
#else
    #define offsetof(s,m) \_\_builtin\_offsetof(s,m)
#endif


Jeg kender ikke betydningen af


#if defined(\_MSC\_VER) && !defined(\_CRT\_USE\_BUILTIN\_OFFSETOF)