- The calling convention keywords __cdecl, __fastcall,
and __stdcall are recognized (as are alternative versions
_cdecl, _fastcall, and _stdcall). Syntactically, these
are treated like pointer declarators and are recognized where
pointer declarators are allowed.
int __cdecl f();
char * __cdecl g();
void (__cdecl *fp)();
Calling conventions are allowed on object declarations, but are
ignored.
- The __inline keyword is recognized (as is the alternate
form _inline).
- The __declspec storage class is recognized. The dllimport,
dllexport, naked, and thread modifiers are recognized
as extended declaration modifiers.
__declspec(dllimport) int f();
declspec(dllexport) void g(){}
__declspec(naked) void h(){}
__declspec(thread) int i;
- The __unaligned keyword is recognized and accepted as
a type qualifier.
- The __based keyword is recognized and information about
based pointer declarations is passed on to the back end. Only
the form __based(variable) is accepted; the other (16-bit
mode) forms are not.
- The Structured Exception Handling statements are recognized:
__try
{ statements; } __finally { statements;
}
__try { statements; } __except( expression
) { statements; }
__leave;
- #pragma pack
is recognized, including the enhanced syntax
that permits the user to manage a stack of packing alignment values
by means of special keywords push and pop. In addition,
packing may be controlled from the command line (see --pack_alignment=n,
which corresponds to /Zpn). (These features are enabled
in
most ports.)
- Two-stage bit-field allocation is done under
a custom porting arrangement.
- Extended support of anonymous unions, including "anonymous
structs" and (in C++) "anonymous classes", is provided
(This
is supported by default (this can be changed under a custom porting
arrangement)).
- End-of-line comments (using // as delimiter) are supported
in C mode.
- A nonconstant may appear in the initializer list of an aggregate
variable with automatic storage class, even in C mode.
- If the final field of a struct is of incomplete array type,
it can be initialized by one or more values in an aggregate initializer
list:
struct S {
int i, j;
int a[];
} x = { 0,0,0,0 };
/* Initializes x.a[0] and x.a[1] to 0. */
(Also, such fields may be declared with [0] instead of [].)
This is allowed in C++ mode only if the class is an aggregate.
- An enumeration type may be declared and then used before its
definition is provided:
enum E x;
E f(E e) { return e; }
enum E { a,b,c };
- Lvalue casts are permitted. In C or C++ modes, casting an
lvalue of integral type to the same integral type yields an lvalue.
In C mode, lvalue casts involving integral types of unequal size
are also allowed.
- asm statements may be of the form:
asm assembly-instruction
asm { assembly-instruction-list }
__asm and _asm
are recognized as synonyms for asm.
- In C mode a warning is issued instead of an error when a function
is redeclared with an incompatible type.
- Type specifiers __int16,__int32, and __int64 are accepted,
as long as there are corresponding integer kinds in the target
environment, and __int8 is treated as equivalent to char
if target chars are defined to have exactly 8 bits.
- When the 16-bit-mode extensions are enabled, near and
far are supported.
int far *p; // p is a "far" pointer
int far x; // x is allocated in the far data segment
int far f(float); // f is called using a far call
_near,
__near, _far, and __far are also accepted.
- The sequence "//" formed during a macro expansion
is treated as the beginning of a comment.
#define COMMENT /##/
COMMENT This is ignored
- Functions returning values of class type in C++ mode are considered
to return lvalues.
- In C mode struct/union tags declared in a prototype scope
are placed in the surrounding file or block scope instead (i.e.,
the C++ rule is used):
int f(struct S *);
int i = f((struct S *)0); /* Okay, same S. */
- In C mode implicit conversions are allowed between pointers
to different types, with a warning.
int f(int *);
int i = f((float *)0); /* Okay, with a warning. */
- The second and third operands of the "?" operator
can be a scalar and a void operand. A warning is issued.
void f();
void g() {
int i = 0;
i ? i : f(); // Okay, with a warning.
}
- When disambiguation requires deciding whether something is
a parameter declaration or an argument expression the declaration
int xyz(int());
declares a function named xyz, that
takes a parameter of type "function taking no arguments and
returning an int." In Microsoft mode this is interpreted
as a declaration of an object that is initialized with the value
int() (which evaluates to zero).
- Extra #else directives (i.e., after the first) encountered
in a skipped section of an #if are ignored, with a warning.
- A storage class (static or extern) is accepted on
a friend function declaration.
- In C mode the enumerator list may be empty in an enum
declaration (i.e., the C++ rule is used).
- In C mode an ellipsis is permitted (but ignored) in an old-style
parameter list declaration, e.g,,
void f(x, ...) int x; { } /* Okay, with a warning. */
- In C mode _alloca is predeclared to accept an argument
of type size_t and return a void * pointer.
- In a functional-notation type conversion, a multi-token type
such as "unsigned int(x)" is accepted.