Вопрос

В этот вопрос, кто-то предложил в комментарий что я должен нет бросить результат malloc, т.е.

int *sieve = malloc(sizeof(int) * length);

скорее, чем:

int *sieve = (int *) malloc(sizeof(int) * length);

Почему это так?

Это было полезно?

Решение

Нет;ты не приведите результат, так как:

  • Это ненужно, так как void * в этом случае автоматически и безопасно повышается до любого другого типа указателя.
  • Это добавляет беспорядка в код, приведения типов не очень удобно читать (особенно если тип указателя длинный).
  • Это заставляет повторяться, что в целом плохо.
  • Это может скрыть ошибку, если вы забыли включить <stdlib.h>.Это может привести к сбоям (или, что еще хуже, нет вызвать сбой в какой-то совершенно другой части кода позже).Рассмотрим, что произойдет, если указатели и целые числа будут иметь разный размер;тогда вы скрываете предупреждение путем приведения и можете потерять часть возвращенного адреса.Примечание:начиная с C11, неявные функции исчезли из C, и этот момент больше не актуален, поскольку не существует автоматического предположения, что необъявленные функции возвращают значения. int.

В качестве пояснения обратите внимание, что я сказал «вы не кастуете», а не «вы не кастуете». нуждаться транслировать".На мой взгляд, это неудачная попытка включить актерский состав, даже если вы все сделали правильно.Пользы от этого просто нет, но куча потенциальных рисков, и включение актерского состава указывает на то, что вы не знаете о рисках.

Также обратите внимание, как отмечают комментаторы, что выше говорится о чистом C, а не о C++.Я твердо верю в C и C++ как в отдельные языки.

Чтобы добавить что-то еще, ваш код без необходимости повторяет информацию о типе (int), что может вызвать ошибки.Лучше разыменовать указатель, используемый для хранения возвращаемого значения, чтобы «связать» их вместе:

int *sieve = malloc(length * sizeof *sieve);

Это также смещает length вперед для большей наглядности и опускает лишние круглые скобки с помощью sizeof;они нужны только когда аргументом является имя типа.Многие люди, похоже, не знают (или игнорируют) этого, что делает их код более многословным.Помнить: sizeof это не функция!:)


Во время движения length спереди может увеличить наглядность в некоторых редких случаях, следует также обратить внимание, что в общем случае выражение лучше писать так:

int *sieve = malloc(sizeof *sieve * length);

С момента сохранения sizeof во-первых, в этом случае гарантирует, что умножение выполняется как минимум size_t математика.

Сравнивать: malloc(sizeof *sieve * length * width) против. malloc(length * width * sizeof *sieve) второй может переполнить length * width когда width и length являются меньшими типами, чем size_t.

Другие советы

В C вам не нужно приводить возвращаемое значение malloc.Указатель на void, возвращаемый malloc автоматически преобразуется в правильный тип.Однако если вы хотите, чтобы ваш код компилировался компилятором C++, необходимо приведение типов.Предпочтительной альтернативой среди сообщества является использование следующего:

int *sieve = malloc(sizeof *sieve * length);

что дополнительно освобождает вас от необходимости беспокоиться об изменении правой части выражения, если вы когда-нибудь измените тип sieve.

Как отмечают люди, актерский состав плохой.Специально приведение указателей.

Ты делать бросил, потому что:

  • Это делает ваш код более портативный между C и C++, и, как показывает опыт SO, очень многие программисты утверждают, что пишут на C, тогда как на самом деле они пишут на C++ (или C плюс локальные расширения компилятора).
  • Не удалось этого сделать может скрыть ошибку:обратите внимание на все примеры SO, которые сбивают с толку, когда писать type * против type **.
  • Идея о том, что это не дает вам заметить, что вы не смогли #include отсутствует соответствующий заголовочный файл лес за деревьями.Это то же самое, что сказать: «Не беспокойтесь о том, что вам не удалось попросить компилятор пожаловаться на отсутствие прототипов — этот надоедливый stdlib.h — это НАСТОЯЩАЯ важная вещь, которую нужно помнить!»
  • Это заставляет дополнительная когнитивная перекрестная проверка.Он помещает (предполагаемый) желаемый тип рядом с арифметикой, которую вы выполняете для необработанного размера этой переменной.Могу поспорить, что вы могли бы провести исследование SO, которое покажет, что malloc() ошибки выявляются гораздо быстрее, когда есть приведение.Как и в случае с утверждениями, аннотации, раскрывающие намерение, уменьшают количество ошибок.
  • Повторение себя таким образом, чтобы машина могла проверить, часто является большой идея.Фактически, это и есть утверждение, и такое использование приведения является утверждением.Утверждения по-прежнему являются наиболее общим методом обеспечения корректности кода, поскольку Тьюринг придумал эту идею много лет назад.

Как уже говорилось, это необходимо не для C, а для C++.Если вы думаете, что собираетесь скомпилировать свой код C с помощью компилятора C++, по каким-либо причинам, вместо этого вы можете использовать макрос, например:

#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif

Таким образом, вы все равно можете написать это очень компактно:

int *sieve = NEW(int, 1);

и он будет скомпилирован для C и C++.

Из Википедия:

Преимущества кастинга

  • Включение приведения может позволить программе или функции C компилироваться как C++.

  • Приведение позволяет использовать версии malloc до 1989 года, которые изначально возвращали символ *.

  • Приведение может помочь разработчику выявить несоответствия в размерах типов в случае изменения типа указателя назначения, особенно если указатель объявлен далеко от вызова malloc() (хотя современные компиляторы и статические анализаторы могут предупреждать о таком поведении, не требуя приведения).

Недостатки кастинга

  • Согласно стандарту ANSI C, приведение типов является избыточным.

  • Добавление приведения может замаскировать невозможность включения заголовка. stdlib.h, в котором найден прототип для Malloc.В отсутствие прототипа для Malloc стандарт требует, чтобы компилятор C предполагал, что Malloc возвращает Int.Если нет актерского состава, предупреждение выдается, когда это целое число присваивается указателю;Однако с актерским составом это предупреждение не производится, скрывая ошибку.На определенных архитектурах и моделях данных (таких как LP64 в 64-битных системах, где длинные и указатели 64-битные, а INT-32-битная), эта ошибка может фактически привести к неопределенному поведению, поскольку неявно объявленная Malloc возвращает 32- битовое значение, тогда как фактически определенная функция возвращает 64-битное значение.В зависимости от вызова конвенций и макета памяти, это может привести к разбиванию стека.Эта проблема с меньшей вероятностью останется незамеченной в современных компиляторах, так как они равномерно выпускают предупреждения о том, что не обнаруженная функция была использована, поэтому все еще будет появляться предупреждение.Например, поведение GCC по умолчанию состоит в том, чтобы показать предупреждение, в котором говорится «несвязанное неявное объявление встроенной функции» независимо от того, присутствует ли актерский состав или нет.

  • Если тип указателя изменяется при его объявлении, можно также изменить все линии, на которых называется Malloc.

Хотя malloc без приведения является предпочтительным методом, и его выбирают большинство опытных программистов., вы должны использовать тот, который вам нравится, зная о проблемах.

то есть:Если вам нужно скомпилировать программу C как C++ (хотя это отдельный язык), вам следует использовать malloc с кастингом.

В C вы можете неявно преобразовать указатель void в указатель любого другого типа, поэтому приведение не требуется.Использование одного из них может подсказать случайному наблюдателю, что существует какая-то причина, по которой он необходим, что может ввести в заблуждение.

Вы не приводите результат malloc, потому что это добавляет бессмысленный беспорядок в ваш код.

Самая распространенная причина, по которой люди приводят результат malloc, заключается в том, что они не уверены в том, как работает язык C.Это предупреждающий знак:если вы не знаете, как работает тот или иной механизм языка, то не Угадай.Посмотрите или спросите на Stack Overflow.

Некоторые комментарии:

  • Указатель void можно преобразовать в любой другой тип указателя или из него без явного приведения (C11 6.3.2.3 и 6.5.16.1).

  • Однако C++ не допускает неявного приведения между void* и другой тип указателя.Таким образом, в C++ приведение типов было бы правильным.Но если вы программируете на C++, вам следует использовать new а не malloc().И никогда не следует компилировать код C с помощью компилятора C++.

    Если вам необходимо поддерживать один и тот же исходный код как C, так и C++, используйте ключи компилятора, чтобы отметить различия.Не пытайтесь снабдить оба языковых стандарта одним и тем же кодом, поскольку они несовместимы.

  • Если компилятор C не может найти функцию, потому что вы забыли включить заголовок, вы получите об этом ошибку компилятора/компоновщика.Итак, если вы забыли включить <stdlib.h> в этом нет ничего страшного, вы не сможете создать свою программу.

  • В древних компиляторах, которые следуют версии стандарта более 25 лет, забывают включить <stdlib.h> приведет к опасному поведению.Потому что в этом древнем стандарте функции без видимого прототипа неявно преобразовывали тип возвращаемого значения в int.Явное приведение результата malloc скроет эту ошибку.

    Но это действительно не проблема.Вы не используете компьютер 25-летней давности, так зачем вам использовать компилятор 25-летней давности?

В C вы получаете неявное преобразование из void* на любой другой указатель (данных).

Приведение значения, возвращаемого malloc() сейчас в этом нет необходимости, но я хотел бы добавить один момент, на который, похоже, никто не указал:

В древности, то есть раньше АНСИ С обеспечивает void * как общий тип указателей, char * это тип для такого использования.В этом случае приведение может отключить предупреждения компилятора.

Ссылка: C Часто задаваемые вопросы

Не обязательно подводить итоги malloc, поскольку он возвращает void* и void* может указываться на любой тип данных.

Просто добавляя свой опыт изучения компьютерной инженерии, я вижу, что два или три профессора, которых я видел, пишущими на C, всегда использовали malloc, однако тот, кого я спросил (с огромным резюме и пониманием C), сказал мне, что это абсолютно ненужно, но Раньше они были абсолютно конкретными и приучали студентов к абсолютной конкретности.По сути, приведение ничего не изменит в его работе, оно делает именно то, что говорит, выделяет память, и приведение не влияет на это, вы получаете ту же память, и даже если вы по ошибке приведете ее к чему-то другому (и каким-то образом уклонитесь от компилятора). ошибки) C получит к нему доступ таким же образом.

Редактировать: Кастинг имеет определенный смысл.Когда вы используете нотацию массива, сгенерированный код должен знать, на сколько ячеек памяти ему нужно продвинуться, чтобы достичь начала следующего элемента. Это достигается путем приведения.Таким образом, вы знаете, что для double вы идете на 8 байт вперед, а для int — на 4 и так далее.Таким образом, это не имеет никакого эффекта, если вы используете нотацию указателя, в нотации массива это становится необходимым.

Это то, что Справочник библиотеки GNU C в руководстве написано:

Вы можете сохранить результат malloc в любую переменную указателя без актера, потому что ISO C автоматически преобразует тип void * к другому типу указателя, когда это необходимо.Но актерский состав необходим в контекстах, кроме операторов назначения, или если вы можете хотеть, чтобы ваш код работал в традиционном C.

И действительно, Стандарт ИСО С11 (p347) говорит так:

Указатель вернулся, если распределение успешных успешных, соответственно выровнен, чтобы его можно было присвоить указателю на любой тип объекта с фундаментальным требованием выравнивания, а затем используется для доступа к такому объекту или массиву таких объектов в распределенном пространстве (до тех пор, пока пространство явно складывается)

Указатель void — это универсальный указатель, и C поддерживает неявное преобразование типа указателя void в другие типы, поэтому нет необходимости явно приводить его к типам.

Однако если вы хотите, чтобы один и тот же код работал идеально совместимо на платформе C++, которая не поддерживает неявное преобразование, вам необходимо выполнить приведение типов, поэтому все зависит от удобства использования.

Возвращаемый тип — void*, который можно привести к нужному типу указателя данных, чтобы его можно было разыменовать.

В языке C указатель void может быть присвоен любому указателю, поэтому не следует использовать приведение типов.Если вам нужно «типобезопасное» распределение, я могу порекомендовать следующие макрофункции, которые я всегда использую в своих проектах на C:

#include <stdlib.h>
#define NEW_ARRAY(ptr, n) (ptr) = malloc((n) * sizeof *(ptr))
#define NEW(ptr) NEW_ARRAY((ptr), 1)

Имея это на месте, вы можете просто сказать

NEW_ARRAY(sieve, length);

Для нединамических массивов третий обязательный функциональный макрос:

#define LEN(arr) (sizeof (arr) / sizeof (arr)[0])

что делает циклы массивов более безопасными и удобными:

int i, a[100];

for (i = 0; i < LEN(a); i++) {
   ...
}

Это зависит от языка программирования и компилятора.Если вы используете malloc в C нет необходимости вводить приведение, поскольку оно автоматически вводит приведение. Однако, если вы используете C++, вам следует ввести приведение, потому что malloc вернет void* тип.

Люди, привыкшие к GCC и Clang, избалованы.Там не все так хорошо.

На протяжении многих лет я был в ужасе от ошеломляюще устаревших компиляторов, которые мне приходилось использовать.Зачастую компании и менеджеры придерживаются ультраконсервативного подхода к изменению составителей и даже не идут на это. тест будет ли в их системе работать новый компилятор (с лучшим соответствием стандартам и оптимизацией кода).Практическая реальность для работающих разработчиков такова, что когда вы пишете код, вам нужно покрыть свои основы, и, к сожалению, приведение mallocs является хорошей привычкой, если вы не можете контролировать, какой компилятор может быть применен к вашему коду.

Я бы также предложил, чтобы многие организации применяли собственные стандарты кодирования и чтобы что должен быть методом, которому следуют люди, если он определен.В отсутствие четких указаний я склоняюсь к тому, чтобы компилировать везде, а не к рабскому следованию стандарту.

Аргумент о том, что в соответствии с действующими стандартами в этом нет необходимости, вполне обоснован.Но этот аргумент упускает из виду практические аспекты реального мира.Мы пишем код не в мире, которым правят исключительно стандарты дня, а практические аспекты того, что мне нравится называть «полем реальности местного управления».И оно искривлено и искривлено сильнее, чем когда-либо было пространство-время.:-)

ЮММВ.

Я склонен думать о применении malloc как о защитной операции.Не красиво, не идеально, но в целом безопасно.(Честно говоря, если вы не включили stdlib.h, значит, вы способ больше проблем, чем кастинг malloc!).

Я ввел приведение просто для того, чтобы показать неодобрение уродливой дыры в системе типов, которая позволяет компилировать такой код, как следующий фрагмент, без диагностики, даже несмотря на то, что никакие приведения не используются, чтобы вызвать плохое преобразование:

double d;
void *p = &d;
int *q = p;

Мне хотелось бы, чтобы этого не существовало (и в C++ его нет), поэтому я применил приведение.Он отражает мой вкус и мою политику в области программирования.Я не только указываю, но и фактически голосую, и изгнание демонов глупости.Если я не смогу на самом деле изгоните глупость, то позвольте мне хотя бы выразить это желание жестом протеста.

На самом деле, хорошей практикой является обертывание malloc (и друзья) с функциями, которые возвращают unsigned char *, и в принципе никогда не использовать void * в вашем коде.Если вам нужен общий указатель на любой объект, используйте char * или unsigned char *, и имеют приведения в обоих направлениях.Пожалуй, единственное расслабление, которым можно побаловать себя, — это использование таких функций, как memset и memcpy без слепков.

Что касается приведения типов и совместимости с C++, то если вы пишете свой код так, чтобы он компилировался как C, так и C++ (в этом случае вы придется привести возвращаемое значение malloc при назначении его чему-то другому, кроме void *), вы можете сделать для себя очень полезную вещь:вы можете использовать макросы для приведения, которые преобразуются в приведения в стиле C++ при компиляции как C++, но сводятся к приведению C при компиляции как C:

/* In a header somewhere */
#ifdef __cplusplus
#define strip_qual(TYPE, EXPR) (const_cast<TYPE>(EXPR))
#define convert(TYPE, EXPR) (static_cast<TYPE>(EXPR))
#define coerce(TYPE, EXPR) (reinterpret_cast<TYPE>(EXPR))
#else
#define strip_qual(TYPE, EXPR) ((TYPE) (EXPR))
#define convert(TYPE, EXPR) ((TYPE) (EXPR))
#define coerce(TYPE, EXPR) ((TYPE) (EXPR))
#endif

Если вы придерживаетесь этих макросов, то простой grep поиск этих идентификаторов в базе кода покажет вам, где находятся все ваши приведения, и вы сможете проверить, не являются ли какие-либо из них неправильными.

Далее, если вы регулярно компилируете код с помощью C++, это будет требовать использования соответствующего приведения.Например, если вы используете strip_qual просто чтобы удалить const или volatile, но программа меняется таким образом, что теперь задействуется преобразование типов, вы получите диагностику, и вам придется использовать комбинацию приведений, чтобы получить желаемое преобразование.

Чтобы помочь вам придерживаться этих макросов, в компиляторе GNU C++ (не C!) есть замечательная функция:дополнительная диагностика, которая создается для всех случаев приведения типов в стиле C.

     -Wold-style-cast (C++ and Objective-C++ only)
         Warn if an old-style (C-style) cast to a non-void type is used
         within a C++ program.  The new-style casts (dynamic_cast,
         static_cast, reinterpret_cast, and const_cast) are less vulnerable
         to unintended effects and much easier to search for.

Если ваш код C компилируется как C++, вы можете использовать это -Wold-style-cast возможность узнать все вхождения (type) синтаксис приведения типов, который может проникнуть в код, и следить за этой диагностикой, заменяя его подходящим выбором из приведенных выше макросов (или их комбинацией, если необходимо).

Такой подход к преобразованиям является крупнейшим независимым техническим обоснованием работы на «Чистом C»:объединенный диалект C и C++, что, в свою очередь, технически оправдывает приведение возвращаемого значения malloc.

Лучшее, что можно сделать при программировании на C, когда это возможно:

  1. Заставьте свою программу компилироваться через компилятор C со всеми включенными предупреждениями. -Wall и исправить все ошибки и предупреждения
  2. Убедитесь, что нет переменных, объявленных как auto
  3. Затем скомпилируйте его с помощью компилятора C++ с помощью -Wall и -std=c++11.Исправьте все ошибки и предупреждения.
  4. Теперь снова скомпилируйте с помощью компилятора C.Теперь ваша программа должна компилироваться без каких-либо предупреждений и содержать меньше ошибок.

Эта процедура позволяет воспользоваться преимуществами строгой проверки типов C++, тем самым уменьшая количество ошибок.В частности, эта процедура заставляет вас включать stdlib.hили ты получишь

malloc не было объявлено в этом объеме

а также заставляет вас привести результат malloc или ты получишь

недопустимое преобразование из void* к T*

или какой у вас целевой тип.

Единственные преимущества написания на C вместо C++, которые я могу найти, это

  1. C имеет четко определенный ABI
  2. C++ может генерировать больше кода [исключения, RTTI, шаблоны, время выполнения полиморфизм]

Обратите внимание, что вторые минусы в идеальном случае должны исчезнуть при использовании подмножества, общего для C, вместе с статический полиморфный признак.

Для тех, кому неудобны строгие правила C++, мы можем использовать функцию C++11 с выводимым типом.

auto memblock=static_cast<T*>(malloc(n*sizeof(T))); //Mult may overflow...

Нет, вы не приводите результат malloc().

В общем, ты не выполнять трансляцию туда или обратно void *.

Типичная причина невыполнения этого требования заключается в том, что неспособность #include <stdlib.h> могло остаться незамеченным.Это уже давно не проблема, поскольку появился C99. неявные объявления функций незаконно, поэтому, если ваш компилятор соответствует как минимум C99, вы получите диагностическое сообщение.

Но есть гораздо более веская причина чтобы не вводить ненужные приведения указателей:

В С, приведение указателя почти всегда является ошибкой.Это связано со следующим правилом (§6.5 стр.7 в N1570, последний проект для C11):

Объект должен иметь свое сохраненное значение, доступное только с помощью выражения LVALUE, которое имеет один из следующих типов:
— тип, совместимый с действующим типом объекта,
— квалифицированная версия типа, совместимая с действующим типом объекта,
- тип, который является подписанным или неподписанным типом, соответствующим эффективному типу объекта,
- тип, который является подписанным или без знаком, соответствующий квалифицированной версии эффективного типа объекта,
- совокупный тип или профсоюзный тип, который включает в себя один из вышеупомянутых типов среди его членов (включая, рекурсивно, член субагрегатного или содержащегося союза), или
— тип персонажа.

Это также известно как строгое правило псевдонимов.Итак, следующий код неопределенное поведение:

long x = 5;
double *p = (double *)&x;
double y = *p;

И, что иногда удивительно, есть еще и следующее:

struct foo { int x; };
struct bar { int x; int y; };
struct bar b = { 1, 2};
struct foo *p = (struct foo *)&b;
int z = p->x;

Иногда вы делать нужно приводить указатели, но учитывая строгое правило псевдонимов, с этим нужно быть очень осторожным.Таким образом, любое появление указателя в вашем коде — это место, где вы придется перепроверить его достоверность.Поэтому вы никогда не пишете ненужное приведение указателя.

вр; доктор

В двух словах:Потому что в Си любой возникновение указатель приведения должен вызывать красный флаг для кода, требующего особого внимания, никогда не следует писать ненужный указатель приводится.


Боковые примечания:

  • Бывают случаи, когда вы на самом деле нуждаться приведение к void *, напримересли вы хотите напечатать указатель:

    int x = 5;
    printf("%p\n", (void *)&x);
    

    Актерский состав здесь необходим, потому что printf() — это вариативная функция, поэтому неявные преобразования не работают.

  • В C++ ситуация иная.Приведение типов указателей довольно распространено (и правильно) при работе с объектами производных классов.Следовательно, имеет смысл, что в C++ преобразование в и из void * является нет скрытый.В C++ имеется целый набор различных вариантов приведения типов.

Я предпочитаю делать слепок, но не вручную.Мой любимый использует g_new и g_new0 макросы из glib.Если glib не используется, я бы добавил аналогичные макросы.Эти макросы уменьшают дублирование кода без ущерба для безопасности типов.Если вы ошибетесь в типе, вы получите неявное приведение между непустыми указателями, что приведет к предупреждению (ошибке в C++).Если вы забыли включить заголовок, определяющий g_new и g_new0, вы получите ошибку. g_new и g_new0 оба принимают одни и те же аргументы, в отличие от malloc это требует меньше аргументов, чем calloc.Просто добавь 0 чтобы получить память с нулевой инициализацией.Код можно скомпилировать компилятором C++ без изменений.

Кастинг предназначен только для C++, а не для C. Если вы используете компилятор C++, лучше измените его на компилятор C.

Концепция указателя void заключается в том, что его можно привести к любому типу данных, поэтому malloc возвращает void.Также вы должны знать об автоматическом приведении типов.Таким образом, приведение указателя не является обязательным, хотя вы должны это сделать.Это помогает поддерживать чистоту кода и помогает в отладке.

  1. Как уже говорилось, это необходимо не для C, а для C++.

  2. Включение приведения может позволить программе или функции C компилироваться как C++.

  3. В C в этом нет необходимости, поскольку void * автоматически и безопасно преобразуется в любой другой тип указателя.

  4. Но если вы примените then, это может скрыть ошибку, если вы забыли включитьstdlib.h.Это может вызвать сбои (или, что еще хуже, не вызвать сбою до тех пор, пока в какой -то другой части кода).

    Потому что stdlib.h содержит прототип для malloc.В отсутствие прототипа для Malloc стандарт требует, чтобы C Компилятор C предполагал, что Malloc возвращает Int.Если нет актерского состава, предупреждение выдается, когда это целое число присваивается указателю;однако при приведении это предупреждение не выдается, что скрывает ошибку.

Указатель void — это универсальный указатель, и C поддерживает неявное преобразование типа указателя void в другие типы, поэтому нет необходимости явно приводить его к типам.

Однако если вы хотите, чтобы один и тот же код работал идеально совместимо на платформе C++, которая не поддерживает неявное преобразование, вам необходимо выполнить приведение типов, поэтому все зависит от удобства использования.

Приведение malloc не требуется в C, но является обязательным в C++.

Приведение типов в C не требуется по следующим причинам:

  • void * автоматически и безопасно повышается до любого другого типа указателя в случае C.
  • Это может скрыть ошибку, если вы забыли включить <stdlib.h>.Это может привести к сбоям.
  • Если указатели и целые числа имеют разные размеры, вы скрываете предупреждение путем приведения и можете потерять биты возвращаемого адреса.
  • Если тип указателя изменяется при его объявлении, возможно, также потребуется изменить все строки, где malloc вызывается и исполняется.

С другой стороны, приведение типов может повысить переносимость вашей программы.то есть он позволяет программе или функции C компилироваться как C++.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top