B20: egcs: Questions (Structures, inline assembly, comments, unnamed unions)

Jonathan Pryor jonpryor@vt.edu
Tue Dec 1 22:50:00 GMT 1998

I'm trying to get the latest Microsoft Platform SDK headers
to compile under egcs-2.91.57, and I came across volumes of 
code that seem to generate errors... :-)

Most of the errors seem to fall into two categories 
(so far...), but there are a couple of other areas that
need help...

First are structures that contain arrays of unspecified size,

	#include <stdio.h>

	typedef struct _TEST {
	    short		Pad;
	    unsigned char	Format[];
	} TEST;

	int main (int, char **) {
	    return 0;

I've looked in Stroustrup (3rd edition) to see if the above
syntax is legal, but found nothing.  Thus, some questions:
 * _Is_ it legal?

 * If not, why not?  (It seems reasonable to me; sure, a 
   pointer would make more sense, but we allow function
   declarations such as
      void some_funct ( char some_text[] );
   so why not allow it in structures?
   BTW, the RPC headers and <winnt.h> seem to make 
   extensive use of this type of construct.)

 * Is there any type of workaround that *doesn't* require
   changing the code?  (I couldn't think of any, but that
   doesn't mean such techniques don't exist...)

Second is the issue of code containing inline assembler.
<sarcasm>In Microsoft's great genious</sarcasm>, they 
decided to insert inline assembler into their headers
(yech!), such as this (from <winnt.h>):

	__inline ULONGLONG
	Int64ShllMod32 (
	    ULONGLONG Value,
	    DWORD ShiftCount
	    __asm    {
	        mov     ecx, ShiftCount
	        mov     eax, dword ptr [Value]
	        mov     edx, dword ptr [Value+4]
	        shld    edx, eax, cl
	        shl     eax, cl

(This is supposed to shift a 64-bit value by a 32-bit value).
While I don't know assembler, the above makes sense -- 
presumably, the code in the __asm { ... } braces will be
inserted directly into the machine-level source before the
program is compiled into machine code.  Not exactly portable,
but it looks better than needing to code an entire routine
in assembler and manually linking it in later (though that's
probably more portable across compilers).  Plus, you get the
compiler to take care of the stack cleanup for you.  Sounds
great to me.

I looked up the g++ `asm' documentation in the man pages, and
was rather confused...

For example, to use the 68881's `fsinx' assembler instruction, 
the following would be needed (from gcc.info-11):

	asm ("fsinx %1,%0" : "=f" (result) : "f" (angle));

This, frankly, looks uglier to me than the inline assembler 
seen above, but opinions aren't under consideration here...

What is under consideration (for me, anyway) is how to get 
this __asm block through g++ *without* modifying the file.

Thus, some questions:
 * why does g++ uses the syntax it currently uses 
   (though this is mostly out of curiosity).

 * is there any way (without modifying the files) to 
   get around this inline assembler?  (Actually, there is a 
   way -- set the _M_ALPHA pre-processor macro, which causes
   <winnt.h> to think it's running on an Alpha, thus it simply
   uses macro's for the functions, as Alpha has native support
   of 64-bit types...  But this still leaves the first question
   about the structures.)

 * how 'bout adding inline assembly braces for g++... :-)
   (Well...maybe not....)

The final issue preventing successful compilation of the
Microsoft Windows headers regards comments.

In the days of yore, they created variables of type VARIANT_BOOL 
named `bool', which of course collides with the C++ type `bool'.
This, of course, wouldn't compile under a C++ compiler, so some
changes were necessary...

The "fix" was to "duplicate" all locations that used VARIANT_BOOL
with a "dummy" _VARIANT_BOOL; the "new" _VARIANT_BOOL declared 
variables with the old name (`bool'), while the VARIANT_BOOL
declared a variable with a non-colliding name.  Thus, older code
wouldn't need to change (unless it was re-compiled with an updated
compiler), e.g.

	typedef union _VARIANT {
		// ...
		_VARIANT_BOOL bool;	// satisfies legacy code
		// ...

So, how to keep the _VARIANT_BOOL line from giving errors?  
By doing this:

	#define _VARIANT_BOOL /##/

Which would have the effect of "commenting out" all lines that
made use of `bool', allowing the VARIANT definition to work
reliably on C++.

Therein lies the problem; when g++ comes across the above
definition of VARIANT (including the `//' to "remove" the line),
it gives an error:

	C:\\usr\\include\\ms\\oaidl.h:421: parse error before `/'

After dumping the pre-processed source to a text file, the error
is on this line:

	//  bool;

Which suggests to me that the g++ compiler doesn't like to deal
with comments, instead expecting the pre-processor to remove them.

Could this be considered a bug?  :-)
(Probably not; such usage -- expecting the pre-processor to 
remove comments -- makes sense, as I'd think it would simplify 
the logic needed to compile the source -- parsing of comments
wouldn't be needed.  Unfortunately it breaks seemingly valid
code like this.  I'd submit that if we tried to use an "older"
pre-processor that didn't handle single line comments, it would
"break" g++...not exactly a good thing.)

Aside from the above three issues, there are some things that
just cause warnings to appear during compilation, which I'm
curious about...

Just out of curiosity, why does g++ give a warning on 
unnamed unions?  It's only a warning (and thus can be ignored),
but it's still annoying seeing dozens of such warnings...

Another warning deals with stack cleanup declarations in
function prototypes; from <oleidl.h>

	IViewObject : public IUnknown
		virtual /* [local] */ HRESULT STDMETHODCALLTYPE 
		Draw (
			// lots of parameters skipped...
				DWORD dwContinue ),
			// ...
		) = 0;
		// ...

STDMETHODCALLTYPE is an alias for __attribute__((stdcall)),
and g++ doesn't seem to like specifying a pointer to a 
`stdcall' function in a function prototype (the definition
of `pfnContinue' gets a warning: "`__stdcall__' attribute 
ignored.".  Very odd...but it's still only a warning.


For the record, if I do modify the headers to get around these
problems (which amounts to using the preprocessor to #define
__int64 as "long long", #define-ing _M_ALPHA, and #define-ing
__unaligned (which only occurs in the Alpha path), and modifying
the files <oaidl.h>, <propidl.h>, <rpcndr.h>, and <winnt.h>),
I can compile the program fine (discounting dozens of warnings,
but it compiles...), and it runs successfully.

For those wondering why I don't use the Windows headers 
included with the CygWin32 utils, I have a couple reasons...
 * The included headers don't include all the API's I need
   (such as the COM API functions.  This is rather interesting
   because the DLL link libraries (libole32.a) include them,
   but the function prototypes aren't in any of the headers.
   e.g. CoInitialize(), CoCreateInstanceEx(), etc...)

 * As Windows changes, it would be nice to have updated 
   headers.  The "closer" to the "source", the faster the 
   updates (I can use the original headers instead of needing
   to wait for someone to re-write the headers into a form I
   can use); In the same beat, if the standard headers can be
   used, then people are free to write other things, instead
   of needing to try to keep up-to-date headers.

Finally, I have been to the site with "fuller" Windows headers 
that compile under g++ 
(at http://www.acc.umu.se/~anorland/gnu-win32/ ) and am using them, 
in fact (thanks to Anders Norlander); however, these are completely 
new and will still need to be maintained; using the Microsoft 
headers would mean that we wouldn't need to keep maintaining our 
own duplicate set.

Thank you for your time
 - Jon

For help on using this list (especially unsubscribing), send a message to
"gnu-win32-request@cygnus.com" with one line of text: "help".

More information about the Cygwin mailing list