Since we are talking about better practices…
I’ll bring up the strategy something like (excuse the email line wrapping):
#define PLATFORM_WINDOWS_BEGIN_ALLOW_BYTE_BITFIELDS __pragma(warning(push));__pragma(warning(disable:4214));
#define PLATFORM_WINDOWS_END_ALLOW_BYTE_BITFIELDS __pragma(warning(pop));
#ifdef PLATFORM_WINDOWS
// set platform specific compiler directives to make strut shape correct
#define PLATFORM_NEUTRAL_BEGIN_PACKED_STRUCT \ PLATFORM_WINDOWS_BEGIN_ALLOW_BYTE_BITFIELDS
#define PLATFORM_NEUTRAL_END_PACKED_STRUC \ PLATFORM_WINDOWS_END_ALLOW_BYTE_BITFIELDS
#endif
We could debate about the pros and cons of push/pop vs enable/disable.
So then your wrap this define around your structure. My experience of making structures platform portable is you need to have some #defined symbols in assorted places, and some platforms may define some of these as empty, and other platforms define them with what’s needed.
If I have to make code initially written in Linux work on Windows, I can get grumpy when I see lots of platform specific constructs spread in a million places. Instead of complaining about non-portable constructs it seems like a better plan to write code that is more portable. The __pragma statement is way better than #pramga as you can use it in a macro definition, and then have a platform appropriate set of #defines
My opinion REALLY is you should NEVER depend on a struct to have a specific memory layout, and you should have functions/objects/macros that pack and unpack a byte pointer to/from your unpacked structure. Explicit code to define the packing and unpacking means you’re documenting what the expected binary layout is. I don’t believe the C spec says anything about how compiler implementations will pack structures. I know it’s common for C code to do this, but based on the C spec, the layout is undefined. C code can be quite portable, if you stop directly using all the little “enhancements” vendors like to make available. Struct packing also does not deal with endian issues. I suppose an argument for struct packing is the debugger will show you the bit fields, although the debugger will not do endian conversion, so you may or may not be able to see the fields in a debugger.
One quite portable C code bitfield strategy I’ve seen was GetBitField/SetBitField macros, that take a buffer pointer, bit offset bit width, and value as parameters. They use a bunch of shifting and masking which looks inefficient but after being optimized by the compiler is pretty much the same code you get from the platform dependent struct shape. These macros also dealt with endian issues, and came in a couple flavors based on what endian the buffers uses.
I also understand there are some really special cases, especially for kernel code, where you will need to control the layout, like certain instructions require the data to be aligned in a certain way. Like if you want some value to be in it’s own cache line.
A better strategy might also be to have things like protocol messages defined in some description language, and you preprocess that language into .c/h files for your specific platform. This has the huge advantage you can also process the message descriptions into the language used by the your network sniffer, so if you change a message during development, the code and the tools all automatically stay in sync. And you can process the message descriptions into documentation. No matter how carefully you make you struct C packing, it still is a C structure, not a language independent description of a memory layout.
Jan
#pragma warning(pop)
Sent from Surface Pro
From: Don Burnmailto:xxxxx
Sent: Thursday, August 28, 2014 12:40 PM
To: Windows System Software Devs Interest Listmailto:xxxxx
Use #pragma warning(disable:4214) … #pragma warning(default:4214) around
the whole structure.
Don Burn
Windows Filesystem and Driver Consulting
Website: http://www.windrvr.comhttp:</http:>
-----Original Message-----
From: xxxxx@lists.osr.commailto:xxxxx
[mailto:xxxxx@lists.osr.com] On Behalf Of
xxxxx@compuserve.commailto:xxxxx
Sent: Thursday, August 28, 2014 12:34 PM
To: Windows System Software Devs Interest List
Subject: [ntdev] Visual Studio 2013 WDK8.1 - bitfields
I’m trying to compile my SCSI tape drivers for 32-bit and 64-bit using
Visual Studio 2013 and WDK 8.1 (don’t laugh). I notice that there are no
tape driver samples in the WDK - or have I missed something?
This doesn’t compile:
typedef struct _MODE_DATA_COMPRESSION_PAGE {
UCHAR PageCode : 6;
UCHAR Reserved1 : 2;
UCHAR PageLength;
UCHAR Reserved2 : 6;
UCHAR DCC : 1;
UCHAR DCE : 1;
UCHAR Reserved3 : 5;
UCHAR RED : 2;
UCHAR DDE : 1;
UCHAR CompressionAlgorithm[4];
UCHAR DecompressionAlgorithm[4];
UCHAR Reserved4[4];
} MODE_DATA_COMPRESSION_PAGE, *PMODE_DATA_COMPRESSION_PAGE;
warning C4214: nonstandard extension used : bit field types other than int
I could put a #pragma warning(suppress:4214) in front of every UCHAR, but
is there a better way? /Ze doesn’t work as it’s been deprecated.
Regards, Richard.
—
NTDEV is sponsored by OSR
Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
OSR is HIRING!! See http://www.osr.com/careers
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at
http://www.osronline.com/page.cfm?name=ListServer
—
NTDEV is sponsored by OSR
Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
OSR is HIRING!! See http://www.osr.com/careers
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer
—
NTDEV is sponsored by OSR
Visit the list at: http://www.osronline.com/showlists.cfm?list=ntdev
OSR is HIRING!! See http://www.osr.com/careers
For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars
To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer</mailto:xxxxx></mailto:xxxxx></mailto:xxxxx></mailto:xxxxx>