Microsoft C 和 C++ 扩展

如本文详述,Microsoft Visual C++ (MSVC) 以多种方式扩展 C 和 C++ 语言标准。

MSVC C++ 编译器默认为 ISO C++14 提供某些 ISO C++17 功能支持和某些特定于 Microsoft 的语言扩展支持。 有关所支持功能的详细信息,请参阅 Visual Studio 版本的 Microsoft C/C++ 语言一致性。 可以使用 /std 编译器选项启用全部 ISO C++17 和 ISO C++20 语言功能支持。 有关详细信息,请参阅/std(指定语言标准版本)

如果指定,可以使用 /Za 编译器选项禁用某些 MSVC C++ 语言扩展。 在 Visual Studio 2017 及更高版本中,/permissive- 编译器选项禁用特定于 Microsoft 的 C++ 语言扩展。 /permissive- 编译器选项由 /std:c++20/std:c++latest 编译器选项隐式启用。

默认情况下,当 MSVC 将代码编译为 C 时,它将使用特定于 Microsoft 的语言扩展实现 ANSI C89。 在 ISO C99 及更高版本中对某些 MSVC 扩展进行了标准化。 可以使用 /Za 编译器选项禁用大多数 MSVC C 扩展,如本文后面的详述。 可以使用 /std 编译器选项启用对 ISO C11 和 C17 的支持。 有关详细信息,请参阅/std(指定语言标准版本)

标准 C 运行时库由 Windows 中的通用 C 运行时库 (UCRT) 实现。 UCRT 还实现了许多 POSIX 和特定于 Microsoft 的库扩展。 UCRT 支持 ISO C11 和 C17 C 运行时库标准,其中包含某些关于实现的注意事项。 它不完全支持 ISO C99 标准 C 运行时库。 有关详细信息,请参阅通用 C 运行时库文档中的兼容性

Keywords

MSVC 将多个特定于 Microsoft 的关键字添加到 C 和 C++ 中。 在关键字列表中,具有两个前导下划线的关键字是 MSVC 扩展。

转换

C++ 编译器和 C 编译器都支持以下类型的非标准转换:

  • C 编译器支持非标准强制转换生成 l 值。 例如:

    char *p;
    (( int * ) p )++;
    // In C with /W4, both by default and under /Ze:
    //     warning C4213: nonstandard extension used: cast on l-value
    // Under /TP or /Za:
    //     error C2105: '++' needs l-value
    

    注意

    此扩展仅适用于 C 语言。 你可以在 C++ 代码中使用以下 C 标准窗体,将指针视为指向其他类型的指针来修改。

    可采用如下方式重新编写前面的示例以符合 C 标准。

    p = ( char * )(( int * )p + 1 );
    
  • C 和 C++ 编译器都支持指向数据指针的函数指针的非标准强制转换。 例如:

    int ( * pfunc ) ();
    int *pdata;
    pdata = ( int * ) pfunc;
    /* No diagnostic at any level, whether compiled with default options or under /Za */
    

变长自变量列表

C 和 C++ 编译器都支持指定可变数量的自变量并后跟提供类型的函数定义的函数声明符:

void myfunc( int x, ... );
void myfunc( int x, char * c )
{ }
// In C with /W4, either by default or under /Ze:
//     warning C4212: nonstandard extension used: function declaration used ellipsis
// In C with /W4, under /Za:
//     warning C4028: formal parameter 2 different from declaration
// In C++, no diagnostic by default or under /Za.

单行注释

C 编译器支持单行注释,它是使用两个正斜杠 (//) 字符引入的:

// This is a single-line comment.

单行注释是 C99 功能。 它们不受 /Za 影响,并且没有任何级别的诊断。

范围

C 编译器支持以下范围相关功能。

  • extern 项重新定义为 static

    extern int clip();
    static int clip() {}
    // In C and C++ with /W4, either by default or under /Ze:
    //     warning C4211: nonstandard extension used: redefined extern to static
    // In C and C++ under /Za:
    //     error C2375: 'clip': redefinition; different linkage
    
  • 在同一范围内使用良性 typedef 重新定义:

    typedef int INT;
    typedef int INT; // No diagnostic at any level in C or C++
    
  • 函数声明符具有文件范围:

    void func1()
    {
         extern double func2( double );
         // In C at /W4:  warning C4210: nonstandard extension used: function given file scope
    }
    int main( void )
    {
         func2( 4 );    //  /Ze passes 4 as type double
    }                  //  /Za passes 4 as type int
    
  • 用非常量表达式初始化的块范围变量的使用:

    int clip( int );
    int bar( int );
    int main( void )
    {
         int array[2] = { clip( 2 ), bar( 4 ) };
    }
    int clip( int x )
    {
         return x;
    }
    int bar( int x )
    {
         return x;
    }
    

数据声明和定义

C 编译器支持以下数据声明和定义功能。

  • 初始化表达式中的混合字符和字符串常量:

    char arr[6] = {'a', 'b', "cde"};
    // In C with /W4, either by default or under /Ze:
    //     warning C4207: nonstandard extension used: extended initializer form
    // Under /Za:
    //     error C2078: too many initializers
    
  • 具有除 unsigned intsigned int 之外的基类型的位域。

  • 没有类型的声明符:

    x;
    // By default or under /Ze, /Za, /std:c11, and /std:c17, when /W4 is specified:
    //     warning C4431: missing type specifier - int assumed. Note: C no longer supports default-int
    //     warning C4218: nonstandard extension used: must specify at least a storage class or a type
    */
    int main( void )
    {
         x = 1;
    }
    
  • 未确定大小的数组作为结构和联合中的最后一个字段:

    struct zero
    {
         char *c;
         int zarray[];
         // In C with /W4, either by default, under /Ze, /std:c11, and /std:c17:
         //     warning C4200: nonstandard extension used: zero-sized array in struct/union
         // Under /Za:
         //     error C2133: 'zarray': unknown size
    };
    
  • 未命名(匿名)结构:

    struct
    {
         int i;
         char *s;
    };
    // By default or under /Ze, /std:c11, and /std:c17, when /W4 is specified:
    //     warning C4094: untagged 'struct' declared no symbols
    // Under /Za:
    //     error C2059: syntax error: 'empty declaration'
    
  • 未命名(匿名)联合:

    union
    {
         int i;
         float fl;
    };
    // By default or under /Ze, /std:c11, and /std:c17, when /W4 is specified:
    //     warning C4094: untagged 'union' declared no symbols
    // Under /Za:
    //     error C2059: syntax error: 'empty declaration'
    

内部浮点函数

当指定 /Oi 时,x86 C++ 编译器和 C 编译器支持 atanatan2cosexploglog10sinsqrttan 函数的内联生成。 这些内部函数不符合标准,因为它们未设置 errno 变量。

ISO646.H 未启用

如果要使用以下运算符的文本形式,则必须在 /Ze 下包括 iso646.h

运算符 文本窗体
&& and
&= and_eq
& bitand
| bitor
~ compl
! not
!= not_eq
|| or
|= or_eq
^ xor
^= xor_eq

这些文本窗体可在 /Za 下或者在指定或隐含 /permissive- 时作为 C++ 关键字提供。

另请参阅

/Za/Ze(禁用语言扩展)
MSVC 编译器选项
MSVC 编译器命令行语法