Расширения Майкрософт для языков C и C++
Обновлен: Ноябрь 2007
Далее перечислены расширения стандартов ANSI C и ANSI C++ в Visual C++.
Ключевые слова
Корпорация Майкрософт добавила в язык C++ несколько дополнительных ключевых слов. Полный список ключевых слов см. в разделе C++ Keywordsсправочнике поя языку C++. Ключевые слова с двумя подчеркиваниями в начале являются расширениями Майкрософт.
Определение статических постоянных целочисленных элементов (static, const или enum) вне класса
По стандарту (/Za) элементы данных следует определять вне класса. Например:
class CMyClass {
static const int max = 5;
int m_array[max];
}
...
const int CMyClass::max; // out of class definition
По стандарту /Ze определение вне класса необязательно для статических (static), целых постоянных (const int) и постоянных перечислений (const enum) элементов данных. Только у статических и постоянных целочисленных элементов и перечислений могут быть инициализаторы внутри класса, а инициализирующее выражение должно быть константой.
Чтобы избегать ошибок при определении вне класса (когда определение вне класса расположено в файле заголовка, а он включается в несколько исходных файлов) необходимо использовать selectany. Например:
__declspec(selectany) const int CMyClass::max = 5;
Приведение типов
Компилятор поддерживает следующие два приведения типов, не включенных в стандарт ANSI.
Использование приведений типов, не включенных в стандарт ANSI, для получения именующего выражения (l-value):
char *p; (( int * ) p )++;
Предыдущий пример можно переписать следующим образом, при этом он будет соответствовать стандарту ANSI C:
p = ( char * )(( int * )p + 1 );
Преобразование указателя функции в указатель данных, не включенное в стандарт ANSI:
int ( * pfunc ) (); int *pdata; pdata = ( int * ) pfunc;
Чтобы выполнить такое же приведение, соответствующее стандарту ANSI, необходимо преобразовать указатель функции в тип int перед приведением в указатель данных:
pdata = ( int * ) (int) pfunc;
Списки аргументов переменной длины
Компилятор поддерживает использование декларатора функции, в котором указывается переменное количество аргументов, за которыми следует определение функции, предоставляющей тип:
void myfunc( int x, ... );
void myfunc( int x, char * c )
{ }
Однострочные комментарии
Компилятор C поддерживает однострочные комментарии, обозначаемые двумя символами косой черты (//):
// This is a single-line comment.
Область действия
Компилятор C поддерживает следующие возможности, связанные с областью действия:
Переопределения элементов extern как static:
extern int clip(); static int clip() {}
Использование мягких переопределений typedef в той же области действия:
typedef int INT; typedef int INT;
У деклараторов функций есть область действия:
void func1() { extern int func2( double ); } 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[5] = {'a', 'b', "cde"};
Битовые поля с базовыми типами, отличными от unsigned int и signed int.
Деклараторы без класса памяти или типа:
x; int main( void ) { x = 1; }
Массивы без указанного размера в качестве последнего поля структуры или объединения:
struct zero { char *c; int zarray[]; };
Безымянные (анонимные) структуры:
struct { int i; char *s; };
Безымянные (анонимные) объединения:
union { int i; float fl; };
Безымянные члены:
struct s { unsigned int flag : 1; unsigned int : 31; }
Встроенные функции с плавающей запятой
Компилятор поддерживает генерирование встроенных функций, ориентированных на системы x86, atan, atan2, cos, exp, log, log10, sin, sqrt и tanEND x86 Specific, если указан параметр /Oi. Для языка C, совместимость со стандартом ANSI теряется при использовании этих встроенных функций, так как они не присваивают значение переменной errno.
Передача неконстантного указателя в функцию, которая ожидает ссылку на константный указатель
Это расширение языка C++. Следующий код компилируется с параметром /Ze:
typedef int T;
const T acT = 9; // A constant of type 'T'
const T* pcT = &acT; // A pointer to a constant of type 'T'
void func2 ( const T*& rpcT ) // A reference to a pointer to a constant of type 'T'
{
rpcT = pcT;
}
T* pT; // A pointer to a 'T'
void func ()
{
func2 ( pT ); // Should be an error, but isn't detected
*pT = 7; // Invalidly overwrites the constant 'acT'
}
ISO646.H не включено
При использовании параметра /Ze необходимо включить файл iso646.h, если требуется использовать текстовые формы следующих операторов:
&& (and)
&= (and_eq)
& (bitand)
| (bitor)
~ (compl)
! (not)
!= (not_eq)
|| (or)
|= (or_eq)
^ (xor)
^= (xor_eq)
Тип адреса строковых литералов — const char [], а не const char (*) []
В следующем примере выводится тип char const (*)[4] с использованием параметра /Za, но если используется параметр /Ze, выводится тип char const [4].
#include <stdio.h>
#include <typeinfo>
int main()
{
printf_s("%s\n", typeid(&"abc").name());
}