что такое расширение файла программного кода c
Блог Евгения Крыжановского
Я научу вас ремонтировать свой компьютер!
Расширения файлов для программных кодов: cpp — это что?
Данный обзор будет посвящен расширению и важности данного параметра для компьютерных систем. Что же особенного в расширении файла? Читатели наверняка смогут почерпнуть для себя массу полезной и интересной информации. Умение разбираться с расширениями довольно важно и может сослужить неплохую службу, о чем и будет идти речь в данном обзоре.
Какое расширение имеет C++?
C ++ это особый язык программирования. У него есть собственное обозначение файлов. Для файлов, написанных на C++ используется обозначение cpp. В данных файлах содержится не скомпилированный код. Такой код еще не готов для использования, его нужно редактировать. Внесение правок в данный код не вызовет сбоев в работе программы. При помощи данного расширения можно узнать, в каком файле содержится код, написанный на C.
Расширение файлов и важность данного объекта в процессе программирования
Зачем вообще нужно используемое компьютером расширение файлов. Персональный компьютер может обрабатывать файлы различных типов при помощи специальных программ и стандартных средств операционной системы. В качестве специального программного обеспечения могут использоваться плагины, которые устанавливаются в интерпретаторы языков программирования и интернет – браузеры. Они позволяют обрабатывать запущенные программы.
Чтобы узнать, какой интерпретатор необходимо использовать, какой машинный код применить для воспроизведения файла, и используются расширения. Машинный код дает возможность распознать тип файла. Эту информацию ему предоставляют реквизиты файла. Так, к примеру, расширение cpp, говорит о том, что документ написан на С++. Интерпретатор после распознавания расширения сможет открыть файл, чтобы пользователь смог с ним работать.
Что собой представляет расширение файла?
Поговорим о том, что собой представляет имя файла с точки зрения компьютерных наук. С назначением расширения мы уже определились: оно служит для идентификации типа и формата файла. Расширение отделяется от имени файла при помощи символа точки. В Windows 95 имелось ограничение на число символов, используемых в расширении. Их должно было быть не больше трех. В современных системах таких ограничений нет. Более того, сегодня один файл может иметь несколько типов расширений. Они будут следовать через точку. Однако к формату cpp это не относится. Мошенники часто используются данную возможность.
Вредоносные файлы довольно часто бывают замаскированы под другие программы, скрывая основной тип расширения файлов. Возможна даже такая ситуация, когда настоящие файлы удаляются или прячутся, а вместо низ появляются совершенно другие. В результате оказывается, что файл с расширением сpp вовсе таковым не является. Чтобы защититься от подобной проблемы, можно использовать программу для показа расширений всех типов. Чтобы включить данную функцию, необходимо использовать «Панель управления». Нужно только найти свойства файлов и выбрать необходимый пункт. Это гарантирует, что ваши файлы не станут лазейкой для проникновения вируса. Необходимо всегда обращать внимание на расширение исполняемых файлов.
Точность информации
В некоторых случаях в расширении бывает не точно указан тип файла. Это приводит к возникновению различных проблем при использовании программ. Так, например, знакомое многим пользователям расширение txt не предоставляет пользователю информацию о том, в какой кодировке написан файл. По этой причине при открытии текстовых документов перед пользователем иногда появляется целый массив непонятных символов. Печально видеть документ в таком состоянии, особенно если он использовался для создания программного кода. В этом случае нужно поменять кодировку файла. Для текстовых документов Word используется одно расширение, которое дает понять, работал пользователь с обычным файлом или отформатированным. Расширение не указывает, какая версия программы была использована. Данный недостаток проявляется только при попытке открыть документы, созданные в более ранних версиях программы в последних версиях.
Другие способы указания формата файла
Существуют и другие возможности указать формат файла. Однако они являются не распространенными. Вряд ли вы о них когда-либо слышали. Сохранять информацию о формате файла можно непосредственно в самой операционной системе. При попытке перейти на другой компьютер, чтобы поработать с данным файлом, могут возникнуть неудобства. Также к подобным способам можно отнести использование метода «магических чисел». При использовании данного метода в файле зашифровывается определенная последовательность байтов, указывающая всю необходимую информацию.
Запись опубликована 09.10.2015 автором katrinas11 в рубрике Программы. Отблагодари меня, поделись ссылкой с друзьями в социальных сетях:
Расширение файла C
C/C++ Source Code Format
Что такое файл C?
Программы, которые поддерживают C расширение файла
Следующий список содержит программы, сгруппированные по 3 операционным системам, которые поддерживают C файлы. Файлы с суффиксом C могут быть скопированы на любое мобильное устройство или системную платформу, но может быть невозможно открыть их должным образом в целевой системе.
Программы, обслуживающие файл C
Как открыть файл C?
Причин, по которым у вас возникают проблемы с открытием файлов C в данной системе, может быть несколько. К счастью, наиболее распространенные проблемы с файлами C могут быть решены без глубоких знаний в области ИТ, а главное, за считанные минуты. Приведенный ниже список проведет вас через процесс решения возникшей проблемы.
Шаг 1. Установите Microsoft Visual Studio программное обеспечение
Наиболее распространенной причиной таких проблем является отсутствие соответствующих приложений, поддерживающих файлы C, установленные в системе. Этот легкий. Выберите Microsoft Visual Studio или одну из рекомендованных программ (например, EditPlus, Borland C++, Eclipse IDE) и загрузите ее из соответствующего источника и установите в своей системе. В верхней части страницы находится список всех программ, сгруппированных по поддерживаемым операционным системам. Одним из наиболее безопасных способов загрузки программного обеспечения является использование ссылок официальных дистрибьюторов. Посетите сайт Microsoft Visual Studio и загрузите установщик.
Шаг 2. Проверьте версию Microsoft Visual Studio и обновите при необходимости
Если у вас уже установлен Microsoft Visual Studio в ваших системах и файлы C по-прежнему не открываются должным образом, проверьте, установлена ли у вас последняя версия программного обеспечения. Иногда разработчики программного обеспечения вводят новые форматы вместо уже поддерживаемых вместе с новыми версиями своих приложений. Это может быть одной из причин, по которой C файлы не совместимы с Microsoft Visual Studio. Все форматы файлов, которые прекрасно обрабатывались предыдущими версиями данной программы, также должны быть открыты с помощью Microsoft Visual Studio.
Шаг 3. Свяжите файлы C/C++ Source Code Format с Microsoft Visual Studio
Если у вас установлена последняя версия Microsoft Visual Studio и проблема сохраняется, выберите ее в качестве программы по умолчанию, которая будет использоваться для управления C на вашем устройстве. Метод довольно прост и мало меняется в разных операционных системах.
Изменить приложение по умолчанию в Windows
Изменить приложение по умолчанию в Mac OS
Шаг 4. Убедитесь, что C не неисправен
Если вы выполнили инструкции из предыдущих шагов, но проблема все еще не решена, вам следует проверить файл C, о котором идет речь. Отсутствие доступа к файлу может быть связано с различными проблемами.
Если C действительно заражен, возможно, вредоносное ПО блокирует его открытие. Рекомендуется как можно скорее сканировать систему на наличие вирусов и вредоносных программ или использовать онлайн-антивирусный сканер. Если сканер обнаружил, что файл C небезопасен, действуйте в соответствии с инструкциями антивирусной программы для нейтрализации угрозы.
2. Проверьте, не поврежден ли файл
Если файл C был отправлен вам кем-то другим, попросите этого человека отправить вам файл. В процессе копирования файла могут возникнуть ошибки, делающие файл неполным или поврежденным. Это может быть источником проблем с файлом. Если файл C был загружен из Интернета только частично, попробуйте загрузить его заново.
3. Убедитесь, что у вас есть соответствующие права доступа
Иногда для доступа к файлам пользователю необходимы права администратора. Войдите в систему, используя учетную запись администратора, и посмотрите, решит ли это проблему.
4. Убедитесь, что в системе достаточно ресурсов для запуска Microsoft Visual Studio
Если система перегружена, она может не справиться с программой, которую вы используете для открытия файлов с расширением C. В этом случае закройте другие приложения.
5. Убедитесь, что у вас установлены последние версии драйверов, системных обновлений и исправлений
Регулярно обновляемая система, драйверы и программы обеспечивают безопасность вашего компьютера. Это также может предотвратить проблемы с файлами C/C++ Source Code Format. Возможно, что одно из доступных обновлений системы или драйверов может решить проблемы с файлами C, влияющими на более старые версии данного программного обеспечения.
Вы хотите помочь?
Если у Вас есть дополнительная информация о расширение файла C мы будем признательны, если Вы поделитесь ею с пользователями нашего сайта. Воспользуйтесь формуляром, находящимся здесь и отправьте нам свою информацию о файле C.
типы файлов, создаваемые для проектов Visual Studio C++
многие типы файлов связаны с Visual Studio проектами для классических настольных приложений. То, какие файлы фактически войдут в ваш проект, зависит от типа проекта и параметров, выбранных при работе с мастером.
при создании проекта Visual Studio можно создать его в новом решении или добавить проект в существующее решение. Нетривиальные приложения обычно разрабатываются как решения, содержащие множество проектов.
Обычно выходным файлом проекта является EXE- или DLL-файл. Проекты могут зависеть друг от друга; в процессе сборки Visual Studio среда проверяет зависимости как внутри, так и между проектами. Каждый проект обычно имеет основной исходный код. В зависимости от типа проекта он может иметь много других файлов, содержащих различные аспекты проекта. Указанием на содержимое этих файлов являются их расширения. В среде разработки Visual Studio по расширениям файлов определяется способ обработки их содержимого в ходе построения.
в следующей таблице показаны общие файлы в проекте Visual Studio и указаны их расширения файлов.
Файлы проекта распределены по папкам в обозревателе решений. Visual Studio создает папку для исходных файлов, файлов заголовков и файлов ресурсов, но вы можете реорганизовать эти папки или создать новые. С помощью папок можно явно создавать логические группы файлов в иерархии проекта. Например, можно создать папки, содержащие все исходные файлы пользовательского интерфейса. Или папки для спецификаций, документации или наборов тестов. Имена папок должны быть уникальными.
При добавлении элемента в проект этот элемент добавляется ко всем конфигурациям этого проекта. Элемент добавляется независимо от того, является ли он создаваемым. Например, если добавить элемент в проект с именем MyProject, то этот элемент появится также в отладочной (Debug) и окончательной (Release) конфигурациях проекта.
Расширения языков C и C++. Часть 1
Данная статья (и я надеюсь что серия статей) посвящена нестандартным расширениям языков C и C++, которые существуют практически в каждом компиляторе.
Языковые расширения — это дополнительные возможности и фичи языка, не входящие в стандарт, но тем ни менее поддерживаемые компиляторами. Исследовать эти расширения очень интересно — в первую очередь потому, что они возникли не на пустом месте; каждое расширение — результат насущной необходимости, возникавшей у большого числа программистов. А мне интересно вдвойне — поскольку мне нравятся языки программирования и я разрабатываю свой, часто оказывается что многие мои идеи реализованы именно в расширениях языка. Стандарты языков C и C++ развиваются крайне медленно, и порой, читая описание расширений, так и хочется воскликнуть «ну это же очевидно! почему этого до сих пор нет в стандарте?».
Языковые расширения — это такая «серая», теневая область, про которую обычно мало пишут и мало знают. Но именно этим она и и интересна!
Предварительно могу сказать, что будут рассмотрены компиляторы общего назначения gcc, msvs, clang, intel, embarcadero, компиляторы для микроконтроллеров iar и keil, и по возможности многие другие компиляторы. Больше всего расширений в GCC, что не удивительно — свободная разработка способствует воплощению разных языковых фич. К тому же, информация по расширениям GCC вся собрана в одном месте, а информацию по остальным компиляторам придется собирать по крупицам. Поэтому начнем с GCC.
Расширения языка Си
Управляющие операторы и блоки кода как выражения
очевиднейшая идея, вовсю применяемая в современных гибридных (императивно-функциональных) языках. Блок кода может быть значением в выражении. Значением считается значение последнего выражения этого блока кода.
Локальные метки
Метки, используемые для оператора goto, по умолчанию имеют область видимости ограниченную функцией. Иногда — например при раскрытии макросов — это небезопасно, и целесообразно ограничить область видимости метки текущим блоком кода. Такие метки требуют предварительного объявления с использованием ключевого слова __label__. Сама метка объявляется обычным образом, но теперь ее область видимости — блок, а не функция.
Метки как значения
Другая интереснейшая и мощнейшая низкоуровневая возможность, связанная с оператором goto — использование меток как значений. Фактически эта возможность существует также только в Ассемблере, где метка — лишь адрес в коде. В GCC однако от специального меточного типа отказались, а для приведения метки к типу void* зачем-то ввели унарный оператор &&. Выглядит весьма красиво и по-хакерски:
Надо сказать, что с подачи Дейкстры оператор goto находится в немилости у большинства программистов. Во многих случаях это действительно оправдано, но не стоит забывать, что Си — хакерский язык, а значит в нем действует идеология предпочтения возможностей ограничениям. И если в каком-то специфическом месте, например в ядре операционной системы, потребуется goto, лучше использовать его, чем городить ассемблерные вставки. А способов испортить код или сделать его нечитаемым великое множество, среди которых goto далеко не на первом месте.
Вложенные функции
Лямбда-функции в C++ появились только в C++11. А между тем еще в Турбо Паскале была возможность вкладывать одни функции в другие. С появлением С++ и классов ничего не изменилось — классы можно было вкладывать в функции и другие классы, но функции в функции вкладывать было по прежнему нельзя. GCC исправляет эту досадную асимметрию в языке.
Вложенные функции поддерживают доступ к переменным объемлющих, но в отличие от лямбд С++ не требуют явного указания «замыканий», и в отличие от лямбд из высокоуровневых языков, не организуют такие «замыкания» автоматически. Еще одна любопытная возможность — goto из вложенной функции в объемлющую. Это больше похоже на прообраз бросания исключения.
Перенаправление вызова с переменным числом аргументов в другую функцию
Специальные языковые конструкции, предназначенные для передачи переменного числа аргументов функции в другую функцию с переменным числом аргументов, при этом информация о количестве аргументов не требуется. Как известно, стандартным способом работы с переменным числом аргументов в Си являются макросы va_start(), va_arg(), va_end() и тип va_list. Способ основан на том, что аргументы функций в Си записываются в стек в обратном порядке, а эти макросы просто предоставляют доступ к памяти стека. Но в данном расширении мы явно видим что-то новенькое. Что же это?
void * __builtin_apply_args () — функция выделяет память на стеке и копирует туда аргументы вызывающей функции.
void * __builtin_apply (void (*function)(), void *arguments, size_t size) — функция принимает блок данных созданный с помощью __builtin_apply_args, указатель на функцию и размер стека для нее; внутри формируется вызов функции с переданными аргументами. Возвращает блок данных на стеке, в котором хранится возвращаемое значение, возвращенное из function.
void __builtin_return (void *result) — функция заменяет обычный return (то есть после этого buildin’а код уже не выполняется) и возвращает результат выполнения function, запакованный в result.
Таким образом, механизм в корне отличается от va_list и может быть применен тогда, когда существует функция с переменным числом аргументов, не имеющая v-версии (то есть версии, принимающей va_list — типа vprintf).
С некоторых пор появились еще два builtin’a, используемых только в inline-функциях, которые жестко инлайнятся всегда (а не на усмортрение компилятора, как это бывает с обычными inline-функиями).
__builtin_va_arg_pack () представляет весь список неименованных аргументов; этот builtin подставляют непосредственно вместо списка аргументов переменной длины.
__builtin_va_arg_pack_len () возвращает количество неименованных аргументов.
Как можно догадаться из требований обязательности inline, эти builtin’ы работают скорее на этапе компиляции, никаких манипуляций со стеком и т.п. в рантайме не производится.
Оператор typeof
Оператор на этапе компиляции возвращает тип выражения. Аналогичный оператор decltype появился таки в С++ не так давно. Однако напомню, что сейчас мы рассматриваем расширения СИ, а не С++! (хотя они конечно же доступны и в gcc c++)
Сокращенный условный оператор
может быть сокращено до:
Это удобная форма записи, особенно если x сам по себе — длинное выражение. Кстати, называется такая форма Elvis operator и она отличается от Null coalescing_operator (существующего например в C#) тем, что Elvis operator приводит первый операнд к типу bool и сравнивает с false, а Null coalescing сравнивает операнд строго со специальным значением null.
Типы __int128 и long long
Еще одно очевидное расширение для 128-битных и 64-битных целых чисел. Тип long long стандартизирован как в С так и в С++, для 128-битных чисел стандарта пока нет. Интересно, если будет, то как он будет называться? long long long и unsigned long long long?
complex
Поддержка комплексных чисел любого типа на уровне языка. Не уверен что такие типы имеет смысл вводить в язык, но напомню — это си, здесь нет нативных объектов, конструкторов, шаблонов и прочего (а по сути это шаблонный тип). В языке введена поддержка суффиксов ‘i’ и ‘j’ (это одно и то же), операторов __real__ и __imag__, а также набора вспомогательных функций.
Достаточно глубокая языковая поддержка позволяет задуматься, а что должно быть в языке для того чтобы можно было комфортно реализовывать и пользоваться такими специальными типами без встраивания напрямую в компилятор.
floating types, half precision
Дополнительные типы с плавающей точкой: __float80, __float128, __fp16.
В самом деле, если открыть стандарт IEEE 754, то окажется что типов несколько больше, чем всем известные float и double (и long double, если кто еще помнит).
Decimal float
Числа с плавающей точкой по основанию 10 применяются в финансовых расчетах, где такие ошибки не должны накапливаться и приводить к утечкам денег.
Hex floats
Это способ записи шестнадцатеричных чисел с плавающей точкой (также связанный с тем, что с помощью десятичной нотации нет возможности записать некоторые числа точно). Вместо буквы ‘e’, занятой для шестнадцатеричной цифры, для экспоненциальной записи применяется буква ‘p’. Как вам например такое число: 0x12c0a34.f09de78p3? По-моему, очень даже по-хакерски.
Fixed point
Числа с фиксированной точкой — еще одно полезное расширение в GCC. На некоторых платформах может не быть FPU, иногда расчеты с фиксированной точкой могут быть быстрее или удобнее. На низком уровне это обычные целые числа, для которых принимается цена разрядов, отличная от общепринятой. Теоретически, можно было бы разрешить любое соотношение целой и дробной частей, но в GCC приняты некоторые конкретные соотношения для основных размеров слов (2, 4 и 8 байт), реализованные в модификаторах типов _Fract и _Accum. К тому же, эта возможность почему-то включена не во все компиляторы, так что проверить эту фичу на практике мне не удалось.
Еще один модификатор _Sat применяется для вычислений с насыщением — это особый режим обработки переполнений, при котором если результат вычислений не влезает в диапазон данного типа, то в переменную сохраняется максимальное или минимальное значение, возможное для данного типа. Точность теряется, но зато не возникает переходов через знак, что может быть предпочтительнее в некоторых случаях (обработка цвета, звука и т.п.)
Именованные адресные пространства
Очень полезная вещь для архитектур с несколькими адресными пространствами. Например для разных микроконтроллеров. Там есть оперативка, flash, eeprom, все это по несколько банков. И независимые систем адресации для каждого адресного пространства.
Массивы нулевой длины
Используются в структурах в качестве последнего элемента, в том случае если структура является заголовком объекта переменной длины. Для низкоуровневого кода очень удобно. В тех случаях если расширение недоступно (в других компиляторах) приходилось делать массив из одного элемента, что вообще говоря некорректно — переменная длина объекта может быть и нулевой. А лишний размер может приводить к ненужным выделениям памяти и т.д.
Пустые структуры
В отличие от С++, где такие структуры разрешены официально, в Си это расширение. И в Си их размер (sizeof) действительно равен нулю, в отличие от С++ где это почему-то 1 байт.
Массивы, размер которых определяется во время выполнения
Очевидная вещь. Имеется функция alloca() которая выделяет память на стеке; ее не нужно освобождать. GCC добавляет возможность объявлять таким образом массивы на уровне языка:
Более того, GCC позволяет объявлять вложенные структуры с полями-массивами переменной длины!
И также функции с массивами переменной длины (где длина указывается в списке аргументов функции):
А если вам хочется указать длину после массива, то и это можно! GCC вводит специальный синтаксис предварительного объявления переменной в списке аргументов функции, кстати крайне интересный для многих других применений (но это уже отдельная тема):
Макросы с переменным числом аргументов
Такие макросы появились в стандарте C99 и C++11. В GCC они появились раньше. Также поддерживаются некоторые улучшения по отношению к стандартной версии. По сути, макрос с переменным числом параметров — это синтаксис, позволяющий передавать в макрос переменное число аргументов и использовать пакет этих аргументов как единое целое для передачи в другие языковые сущности, поддерживающие переменное число аргументов (функции, другие макросы а в С++ еще и шаблоны). В декларации макроса пакет аргументов обозначается как три точки «. «, а в теле — как идентификатор __VA_ARGS__.
Теперь о расширениях. Первое — вместо трех точек и __VA_ARGS__ можно использовать нормальные имена, которые декларируются с тремя точками, а используются без них. Это улучшает читаемость кода, и вообще очень красивая идея сама по себе.
Второе — правильная работа с «завершающими запятыми». При любой кодогенерации (а макросы это тоже кодогенерация) неизбежно возникают ситуации, когда в конце списка каких-либо объектов оказывается запятая. По уму, языкам программирования следует считать эту ситуацию нормальной, но к сожалению большинство языков (и Си в том числе) рассматривают это как ошибку. Поэтому придумали костыли — специальный синтаксис ##__VA_ARGS__, который убирает запятую в том случае если пакет аргументов пустой.
Облегченные правила для переноса строк в препроцессоре
Препроцессор сам по себе — вещь весьма некрасивая и опасная (о чем я регулярно упоминаю в комментариях к разным статьям). но раз он есть — то вполне логично облегчить некоторые строгие требования. В частности, препроцессор в Си для реализации многострочных макросов использует весьма странный и дурацкий синтаксис с бэкслешами. Данное расширение разрешает наличие пробельных символов после бэкслешей (символы-то невидимые, легко в процессе правки кода их туда случайно ввести и не заметить).
Индексация не-lvalue массивов
Сейчас это кажется очевидным, но в С90 почему-то нельзя было индексировать не-lvalue массивы. К счастью, и в С99, и в С++ это возможно.
Арифметика с указателями void* и указателями на функции
Разрешены арифметические операции над такими указателями. Размер адресуемых объектов принимается равным 1 байту (но из этого следует странное следствие: sizeof(void) и sizeof от функционального типа равны 1… что не есть хорошо).
Указатели на массивы с квалификаторами
Тонкости и отличия от стандарта реализации работы с указателями на массивы с квалификаторами (const и другими) в GCC C.
Не константные инициализаторы
Очевидная вещь, но по стандарту нельзя использовать в списках инициализации (в фигурных скобках) неконстантные объекты. Данное расширение открывает такую возможность:
Составные литералы
Еще одна очевиднейшая вещь, к которой все приближаются с разных сторон, но никак не могут реализовать окончательно, бесповоротно и правильно (что самое главное). Составные литералы, которые можно использовать в качестве объектов массивов, функций и объединений — не только для инициализации, но и просто в коде — для присваивания, передачи в качестве аргументов функций.
Для таких литералов создаются временные объекты соответствующего типа, которые и участвуют в выражениях; поэтому возможно например такое (казалось бы невозможное, т.к. константа не lvalue):
Обозначенные (designated) элементы в списках инициализации
И еще одно красивое расширение списков инициализации — внутри списков можно указывать не только все элементы подряд, но и конкретные элементы, используя синтаксис десигнаторов. Для массивов это унарные квадратные скобки, в которых указывается индекс элемента. Так.
Можно использовать диапазоны:
Для структур используется аналогичный синтаксис с унарной точкой:
Можно смешивать оба типа десигнаторов, а также в одном списке инициализации использовать как десигнаторы так и просто элементы:
Кстати, это расширение не реализовано в C++ и его так и не протащили в стандарт. А жаль, это одно из самых красивых расширений, и одна из вещей которые теперь есть в Си и нет в С++.
Диапазоны в case
Возможность использовать диапазоны (с троеточием) в операторе switch в качестве аргументов case:
забавно, но авторы GCC рекомендуют окружать троеточие пробелами, ссылаясь на то что иначе могут быть проблемы с парсингом целых чисел (вероятно боятся что числа будут распознаны как вещественные). При правильном парсинге такого быть не должно, более длинные операторы должны иметь приоритет над короткими начинающимися с тех же символов. Ну да ладно.
Приведение к типу объединения любого объекта, являющегося членом объединения
Если имеется объединение:
То можно осуществлять явное приведение типа объектов int и double к типу foo:
Аналогично при передаче аргументов в функцию:
Смешивание объявления переменных и кода
Привычнейшая в С++ вещь в C90 оказывается тоже являлась расширением (в С99 ее включили в стандарт).
Атрибуты функций, переменных, типов, меток, перечислений, управляющих операторов
Специальное ключевое слово __attribute__, позволяющее назначать определенные компилятором атрибуты (метаинформацию) различным языковым конструкциям. После ключевого слова в круглых скобках указывается имя атрибута. Атрибуты могут быть самые различные. Некоторые атрибуты общие, другие специфичны для конкретной архитектуры. Атрибуты также могут иметь аргументы, которые указываются в круглых скобках после имени атрибута. Вот некоторые атрибуты (на самом деле их очень много и, возможно, эта тема достойна отдельной статьи).
noreturn, — фукнция никогда не возвращает управление,
pure — функция без побочных эффектов (значение зависит только от аргументов),
format — имеет аргументы в стиле форматной строки printf;
unused — метка не используется для перехода с помощью goto.
hot — переход по метке имеет высокую вероятность
cold — переход по метке имеет низкую вероятность
deprecated — элемент не рекомендуется к использованию, при его использовании в коде будет предупреждение
fallthrough — используется в операторе switch/case и ставится вместо break, чтобы указать компилятору что здесь намеренно нет break.
Объявление прототипов совместно с определениями функций в старом стиле
Костыль совместимости со старым Си, позволяющий объявлять прототип функции в новом стиле, при том что тело функции определено в старом стиле (аргументы в круглых скобках без типов, затем отдельно аргументы с типами и затем тело в фигурных скобках).
Комментарии в стиле C++
Вы не поверите, но вообще говоря это тоже расширение — оставшееся с тех древних времен, когда однострочные комментарии еще не входили в стандарт Си. Да, были и такие времена.
Символ доллара в идентификаторах
Не знаю имеет ли это смысл (операторных символов и так мало), но вот так — в идентификаторах вместе с буквами, цифрами и символом подчеркивания можно использовать и символ доллара.
Символ Escape
Запрос выравнивания полей типа или переменной
Ключевое слово __alignof__ возвращает выравнивание, требуемое для поля в некотором типе или просто для некоторого типа. Выравнивание 1 — по границе байта (самое минимально возможное), 2 — по границе слова, 4 — по границе двойного слова и т.д.
inline-функйции
Это всем известная возможность С++, перенесенная в Си.
Использование volatile
Некоторые особенности использования volatile в GCC. Из любопытного — если в коде встречается такое:
то GCC интерпретирует это как чтение из памяти, на которую указывает ptr, и генерирует соответствующий код
Использование ассемблерных вставок
Рассмотрены вопросы использования ассемблерных вставок в GCC; сама тема ассемблерных вставок, насколько мне известно, не является частью какого-либо стандарта, и достаточно обширна для изложения здесь. Надо сказать, что ассемблерные вставки — это частный случай вставок на другом языке вообще; это точка пересечения двух синтаксисов, которые могут в некотрых случаях даже оказаться несовместимыми. Видимо по этой причине в GCC ассемблерные вставки заключены в кавычки, как строки.
Альтернативные ключевые слова для заголовочных файлов
Какой-то очередной костыль совместимости с разными стандартами. Слова __const__, __asm__, и т.д.
Незавершенные перечисления
Можно объявить enum без элементов; объявлять переменные такого типа нельзя, но можно объявлять указатели на такие перечисления. Сделано для возможности предварительного объявления имени перечисления, по аналогии со структурами и объединениями.
Имена функций в виде строк
Это зачатки рефлексии в Си. Идентификаторы __FUNCTION__ (или __func__) и __PRETTY_FUNCTION__ содержат имя той функции, в которой они используются. __PRETTY_FUNCTION__ содержит расширенное имя — сигнатуру.
Получение адресов вызывающих функций и стековых фреймов
Реализация доступа к стеку вызовов функций. Специальные встроенные функции (built-in’ы) используются для получения адресов возврата нужного уровня (вызывающей функции, функции вызвавшей вызывающую и т.д.), а также адреса стековых фреймов функции и всех вызывающих фунцкий.
Расширения для векторных инструкций
Многие процессоры поддерживают векторные типы данных и инструкции (например SIMD — single instruction, multiple data).
Данное расширение поддерживает объявление векторных типов (с помощью атрибута vector_size) и далее использование обычных операций над этими типами. Типы по сути являются массивам, но операции над ним подобны операциям над обычными переменными. Тем ни менее доступна индексация как в массиве.
Также доступна специальная встроенная функция __builtin_shuffle для перестановки элементов в векторе или формировании одного вектора из двух согласно индексной маске:
Специальный синтаксис для offsetof
Оператор offsetof, возвращающий смещение поля в байтах от начала структуры, может быть реализован макросом вида:
Однако, это является неопределенным поведением по стандарту Си (из-за разыменования нуля) и также приводит к различным нежелательным предупреждениям компилятора; поэтому для реализации offsetof используется встроенная функция __builtin_offsetof
Различные встроенные функции (builtins)
Это понятие редко выделяется в самостоятельную сущность — а зря. Встроенные функции занимают промежуточное место между ключевыми словами языка и обычными функциями и используются повсеместно, и большинство программистов даже не задумывается об их природе.
Например синус sin(). Визуально это функция, ведет себя как функция (можно даже взять адрес) Однако на уровне компилятора эта конструкция преобразуется в одну или несколько ассемблерных команд FPU, а никак не в вызов функции (за исключением случаев эмуляции FPU для тех архитектур, которые не поддерживают плавающую точку). Такие функции называются встроенными (builtin) и генерируются непосредственно компилятором, что позволяет реализовать функциональность, недоступную для библиотечных функций. Сюда относятся функции для атомарного доступа к памяти, проверки арифметических переполнений, расширение Cilk Plus, математиченские функции, множество функций для работы с конкретными платформами и процессорами и т.д.
Прагмы
Прагмы — директивы, предназначенные в общем случае для тонкого управления процессом компиляции непосредственно из исходников; их можно отнести и к препроцессору, и к самому языку (на самом деле мне сложно отнести их куда-то однозначно, да и препроцессор давно уже слился с языком). GCC поддерживает как прагмы общего назначения, так и для конкретных платформ. Тема большая и интересная, также как и builtin’ы, так что возможно она будет рассмотрена в отдельной части.
Безымянные поля структур и объединений
В структурах и объединениях можно объявлять вложенные безымянные структуры и объединения. Поля этих вложенных структур и объединений будут доступны напрямую:
Следует отметить, что это работает только до тех пор пока структура безымянная; стоит дать ей имя, и такое объявление превратится в объявление вложенной структуры внутри пространства имен объемлющей, то есть логика вложенности поменяется с вложенности данных на вложенность пространств имен.
А если в опциях компилятора включить режим расширений Plan9 («-fplan9-extensions»), то окажется можно делать вещи, доступные сейчас пожалуй лишь в языке Go: встраивание (embedding) одних структур в другие, что по сути является продвинутой версией наследования — в поля структуры можно встроить целиком поля другой структуры и обращаться к ним как к собственным полям структуры, при этом, в отличие от наследования С++, можно точно указать то место, в которое должны встраиваться поля (что немаловажно для низкоуровневых целей).
Thread-Local переменные
По сути статические переменные потока, хранящиеся в области памяти потока thread-local storage. Если есть такое явление как потоки и TLS, то должно быть и ключевое слово для объявления там переменных.
Двоичные литералы
Одна из простейших и очевиднейших вещей, которая должна была появиться вместе с языком Си в далеких семидесятых. Но не появилась. Для констант используется префикс ‘0b’.
Тут стоит заметить, что для восьмеричных констант стоило бы ввести префикс ‘0o’ даже несмотря на то что есть официальный способ. Способ записи с начальным нулем ужасен.
Расширения gcc с++
Использование volatile
Некоторые особенности использования volatile в GCC C++, отличия от Си.
Ограниченные указатели (из C99)
Ключевое слово restrict позволяет программисту сообщить компилятору, что объявляемый указатель указывает на блок памяти, на который не указывает никакой другой указатель. Гарантию того, что на один блок памяти не будет указывать более одного указателя, даёт программист. При этом оптимизирующий компилятор может генерировать более эффективный код.
В расширении GCC можно также создавать restrict ссылки и применять его для указателя this.
«Неопределенная» (vague) линковка
Некоторые конструкции в С++ требуют места в объектных файлах и могут оказаться одновременно в нескольких единицах трансляции. Это inline-функции, таблицы виртуальных функций (VTables), объекты type_info и результаты инстанцирования шаблонов. GCC поддерживает размещение таких объектов в COMDAT секции объектного файла, что позволяет исключить дубликаты объектов на этапе линковки.
Прагмы interface и implementation
Такие прагмы позволяют явно указать компилятору, является ли объект интерфейсом или реализацией. Дополнительный костыль к «неопределенной линковке».
Инстанцирование шаблонов
Методы инстанцирования шаблонов в GCC. Методы, гарантирующие, что будет сгенерирована только одна копия каждого экземпляра шаблона для конкретных параметров шаблона. Тема большая, здесь только упомяну.
Извлечение указателя на функцию из указателя на функцию-член класса
Очевидное расширение возможностей, связанных с операциями ‘->*’ и ‘.*’. Если указатель на поле класса на низком уровне представляет собой байтовое смещение этого поля внутри класса, то указатель на метод — это полноценный указатель на функцию, и GCC добавляет возможность приводить тип указателя на метод к обычному указателю на функцию.
Атрибуты С++
Некоторые атрибуты (задаваемые через ключевое слово __attribute__), применимые только для C++. Несколько примеров: abi_tag — способ задания манглинга имен переменных и функций; init_priority — приоритет инициализации для глобальных объектов.
Объявление множества версий функции
Любопытная возможность. С помощью атрибута target можно объявить несколько версий одной и той же функции — в зависимости от особенностей процессора (например наличия поддержки того или иного набора команд, той или иной модели процессора и т.д.). Чем-то похоже на условную компиляцию, но компилируются все функции, а нужная выбирается во время выполнения программы.
Ассоциированные пространства имен
Возможность эквивалентная inline namespace (поэтому в следующих версиях GCC нестандартная реализация будет удалена).
Признаки типов (Type Traits)
Поддержка на уровне компилятора специальных конструкций, позволяющих во время компиляции получать различню информацию о типе. Их достаточно много, и пожалуй имеет смысл рассмотреть эту тему отдельно (особенно в сравнении с аналогичными конструкциями, реализованными на шаблонах, и аналогичными конструкциями языка D). Чтобы было понятно о чем речь — вот несколько штук:
Концепты С++
Мощнейшая фича, не попавшая к сожалению в последний (С++17) стандарт. Способ явно задать ограничения на аргументы шаблонов (т.е. ввести своеобразную типизацию шаблонов), и тем самым сделать метапрограммирование проще и понятнее.
Не рекомендованные к использованию или уже удаленные возможности
Тоже интересно. Эти возможности или удалены, или объявлены не рекомендованными к использованию и будут удалены в ближайшее время.
Обратная совместимость
Некоторые особенности обратной совместимости с предыдущими версиями С++ и С. Эти возможности включаются специальными опциями компилятора.
На этом пока все
Как видно, некоторые расширения даже сложно назвать расширениями: это или всем известные фичи, или — что еще хуже — костыли, призванные обеспечить совместимость с какими-то древними и унаследованными стандартами, обойти неудачные решения в дизайне языка и т.д.
В то же время другие — поистине жемчужины среди языковых фич, и очень жаль что их не включают в стандарт.