Может ли код, действительный как на C, так и на C ++, вызывать различное поведение при компиляции на каждом языке?

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

(От "действительный» Я имею в виду стандартный код с определенным поведением, то есть не зависящим от реализации / неопределенным / и т. Д.)

Есть ли сценарий, в котором кусок кода, действительный как на C, так и на C ++, произведетразные поведение при компиляции со стандартным компилятором на каждом языке?

Чтобы сделать это разумное / полезное сравнение (яя пытаюсь выучить что-то практически полезное, а не пытаться найти очевидные лазейки в вопросе), давайтеПредположим, что:

Ничего не связанного с препроцессором (что означает отсутствие взлома с#ifdef __cplusplus, прагмы и пр.)Все, что определено реализацией, одинаково для обоих языков (например, числовые ограничения и т. Д.)Мы'сравнивая разумно последние версии каждого стандарта (например, C ++ 98 и C90 или более поздние версии)

Если версии имеют значение, пожалуйста, укажите, какие из версий имеют различное поведение.
 jamesdlin31 авг. 2016 г., 07:39
 Kaz15 окт. 2012 г., 09:59
Кстати, может быть полезно программировать на диалекте, который является C и C ++ одновременно. Я'мы делали это в прошлом и один текущий проект: язык TXR. Интересно, что разработчики языка Lua сделали то же самое, и они называют этот диалектЧистый С ", Вы получаете преимущество лучшей проверки времени компиляции и, возможно, дополнительной полезной диагностики от компиляторов C ++, но сохраняете переносимость C.
 Marc24 февр. 2009 г., 00:52
Было бы полезно, если бы вы предоставили версии компилятора и параметры командной строки компилятора?
 dmckee17 окт. 2012 г., 00:19
@AndersAbel Чистое количество ответов, все из которых являются правильными, однозначно демонстрирует, что это остается вопросом «составить список». Вы не могли бы задать этот вопрос, не получив список.
 JJJ15 окт. 2012 г., 12:37
int main() { printf("Hi!\n"); /* no return here */ } отличается в C90 (не в C99) и C ++ (попробуйтеecho $?). Но это не действует и UB в случае C90.
 George Stocker16 окт. 2012 г., 02:37
Я слил старый вопрос в этот вопрос, так как у него больше мнений и ответов с повышенным голосованием. Это все еще пример неконструктивного вопроса, но этоэто довольно погранично, так как да, это действительно чему-то учит пользователей. Я'Я закрываю это как не конструктивное только для отражения состояния вопроса до слияния. Не стесняйтесь не соглашаться и вновь открывать.
 Johannes Schaub - litb24 февр. 2009 г., 00:53
наоборот: в C структуры не являются областями видимости, поэтому структура A внутри структуры B называется "структура А " поэтому C ответит 512, а C ++ скажет 8.
 Anders Abel16 окт. 2012 г., 17:39
Голосование возобновить, поскольку я думаю, что на него можно объективно ответить "да" сопровождаемый примером (как доказано ниже). Я думаю, что это конструктивно, потому что люди могут извлечь из этого соответствующее поведение.
 dmckee17 окт. 2012 г., 00:21
@GeorgeStocker "Я слил старый вопрос в этот вопрос, поскольку у него больше мнений и ответов ". Это просто побуждает людейне искать прежде чем спрашивать Если оно'Дубликат ты просто говоришь "Ой! Я не'не знаю. " и потому что сайт стал в сто раз больше, теперь выигрывает новый.
 George Stocker17 окт. 2012 г., 03:19
@dmckee За что этоЯ согласен с вами. Тем не менее, люди с тегами C ++ ... Скажем так ...злющий.
 P.P.17 февр. 2013 г., 03:18
 Adrian McCarthy20 апр. 2018 г., 01:36
Кроме тогоautoкажется, должен быть способ использовать некоторые из ключевых слов C ++, которые неt ключевых слов в C (или наоборот):newdeleteoperatorusing, так далее.
 Mehrdad27 июл. 2018 г., 21:31
@AdrianMcCarthy: яя не уверен, чтовозможно ... для этого "Работа" вы'Мне нужно точно такое же выражение, использующее эти слова, чтобы интерпретировать их как ключевые слова и как идентификаторы, по крайней мере, если вы неиспользовать трюк уже в одном из ответов (в этом случае яя бы поспорилповторяющийся трюк). Это в основном синтаксическая вещь, а не семантическая вещь ... и это неЭто кажется возможным, учитывая, что синтаксис C почти полностью является подмножеством синтаксиса C ++ (даже в большей степени, чем семантика). Но я'я не уверен, я могуЯ совершенно исключаю это ...

Ответы на вопрос(19)

Встроенные функции в C по умолчанию имеют внешнюю область, а не те, что в C ++.

Компилирование следующих двух файлов вместе выведет "Я в строке " в случае GNU C, но ничего для C ++.

Файл 1

#include 

struct fun{};

int main()
{
    fun();  // In C, this calls the inline function from file 2 where as in C++
            // this would create a variable of struct fun
    return 0;
}

Файл 2

#include 
inline void fun(void)
{
    printf("I am inline\n");
} 

Кроме того, C ++ неявно относится к любомуconst глобальный какstatic если это явно не объявленоexternв отличие от C, в которомextern по умолчанию.

 Seth Carnegie15 окт. 2012 г., 18:10
Каково различное поведение встроенных функций иextern что здесь продемонстрировано?
 Alex B16 окт. 2012 г., 01:36
@fayyazkl Показанное поведение только из-за разницы в поиске (struct fun противfn) и не имеет никакого отношения к тому, является ли функция встроенной. Результат идентичен, если вы удалитеinline Классификатор.
 M.M09 мая 2016 г., 06:28
В ISO C эта программа плохо сформирована:inline не был добавлен до C99, но в C99fun() не может быть вызван без прототипа по объему. Поэтому я предполагаю, что этот ответ относится только к GNU C.
 fayyazkl15 окт. 2012 г., 18:01
Я действительно неЯ так не думаю. Возможно, вы упустили момент. Это'не об определении структуры st, которая просто используется, чтобы сделать код допустимым c ++. Дело в том, что он подчеркивает различное поведение встроенных функций в c vs c ++. То же относится и к extern. Ни одно из них не обсуждается ни в одном из решений.
 fayyazkl15 окт. 2012 г., 18:12
Это написано довольно четко. "Встроенные функции в c по умолчанию имеют внешнюю область видимости, в отличие от функций в c ++ (код показывает это). Кроме того, C ++ неявно рассматривает любой глобальный const как область видимости файла, если он явно не объявлен как extern, в отличие от C, в котором extern является значением по умолчанию. Аналогичный пример может быть создан для этого ", Я озадачен - Разве это не понятно?

Язык программирования C ++ (3-е издание) приводит три примера:

SizeOf ( 'а'), как упомянул @ Адам Розенфилд;

// комментарии, используемые для создания скрытого кода:

int f(int a, int b)
{
    return a //* blah */ b
        ;
}

Структуры и т. Д. Прячут вещи в области видимости, как в вашем примере.

int main(void) {
    const int dim = 5; 
    int array[dim];
}

Это довольно своеобразно тем, что оно действительно в C ++ и в C99, C11 и C17 (хотя и необязательно в C11, C17); но не действует в C89.

В C99 + он создает массив переменной длины, который имеет свои особенности по сравнению с обычными массивами, так как он имеет тип времени выполнения вместо типа времени компиляции, иsizeof array не является целочисленным константным выражением в C.

Пустые структуры имеют размер 0 в C и 1 в C ++:

#include 

typedef struct {} Foo;

int main()
{
    printf("%zd\n", sizeof(Foo));
    return 0;
}
 Antti Haapala27 нояб. 2018 г., 06:56
Нет, разница в том, что С делаетне имеют пустые структуры, за исключением расширения компилятора, т. е. этот код не соответствуетдействует как на C, так и на C ++

Согласно стандарту C ++ 11:

а. Оператор запятой выполняет преобразование lvalue в rvalue в C, но не в C ++:

   char arr[100];
   int s = sizeof(0, arr);       // The comma operator is used.

В C ++ значение этого выражения будет 100, а в C это будет.sizeof(char*)

б. В C ++ тип перечислителя - это его перечисление. В С типом перечислителя является int.

   enum E { a, b, c };
   sizeof(a) == sizeof(int);     // In C
   sizeof(a) == sizeof(E);       // In C++

Это означает, чтоsizeof(int) не может быть равен.sizeof(E)

с. В C ++ функция, объявленная с пустым списком параметров, не принимает аргументов. В C пустой список параметров означает, что количество и тип функциональных параметров неизвестен.

   int f();           // int f(void) in C++
                      // int f(*unknown*) in C
 Mankarse15 окт. 2012 г., 13:49
Это легко исправить - просто измените пример на:char arr[sizeof(char*)+1]; int s = sizeof(0, arr);
 Owen18 окт. 2012 г., 02:17
@SethCarnegie или просто сделайте одно и то же дважды для различной длины массива, так как sizeof (char *) может 'быть таким же, как они оба.
 Kerrek SB20 янв. 2014 г., 00:42
Объявление а): в C это 'только что называетсяпреобразование lvalue ", Значения в C являются либо lvalues, либо "не lvalue ".
 Seth Carnegie15 окт. 2012 г., 03:00
Первый также определяется реализацией, как Алексейs. Но +1.
 finnw15 окт. 2012 г., 14:48
Чтобы избежать различий, связанных с реализацией, вы также можете использоватьvoid *arr[100], В этом случае элемент имеет тот же размер, что и указатель на тот же элемент, поэтому, если имеется 2 или более элементов, массив должен быть больше адреса его первого элемента.
 Seth Carnegie15 окт. 2012 г., 03:31
Да, но это все еще определяется реализацией.sizeof(char*) может быть 100, и в этом случае первый пример будет производить то же наблюдаемое поведение в C и C ++ (т.е. метод полученияs было бы по-другому,s в конечном итоге будет 100). ОП упомянул, что этот тип поведения, определяемого реализацией, был хорош, поскольку он просто хотел избежать ответов юристов, поэтому первый вариант подходит для его исключения. Но второй хорош в любом случае.
 Kirill Kobelev15 окт. 2012 г., 03:13
@ Seth, Все вышеперечисленные материалы взяты непосредственно из Приложения C.1 стандарта C ++ 11.

Для C ++ и C90 существуетпо крайней мере, один способ получить другое поведение, котороене определена реализация. С90 нене иметь однострочных комментариев. С небольшой осторожностью мы можем использовать это для создания выражения с совершенно разными результатами в C90 и C ++.

int a = 10 //* comment */ 2 
        + 3;

В C ++ все от// в конце строки находится комментарий, так что это работает так:

int a = 10 + 3;

Поскольку С90 нене иметь однострочных комментариев, только/* comment */ это комментарий. Первый/ и2 обе части инициализации, так что получается:

int a = 10 / 2 + 3;

Таким образом, правильный компилятор C ++ даст 13, но строго правильный компилятор C90 8. Конечно, я просто выбрал здесь произвольные числа - вы можете использовать другие числа по своему усмотрению.

 sehe15 окт. 2012 г., 13:53
@RyanThompson Trivial. с / 2/1 /
 Ale08 окт. 2014 г., 01:08
@ Mehrdad Я не прав или комментарии связаны с препроцессором? Таким образом, они должны быть исключены в качестве возможного ответа на ваш вопрос! ;-)
 OJFord08 апр. 2015 г., 14:02
@ Эле Правильно, но, может быть, слишком много придирки. Я думаю "не cpp " Правило означало больше какнет директив cpp ".
 Mehrdad15 окт. 2012 г., 08:06
Вау это умопомрачительно !! Из всех возможных вещей, о которых я никогда бы не подумал, комментарии могут быть использованы для изменения поведения, хаха. +1
 Benoit15 окт. 2012 г., 09:44
даже без2было бы читать10 / + 3 который действителен (унарный +).
 Ryan Thompson15 окт. 2012 г., 11:59
Теперь ради интереса, измените его так, чтобы C и C ++ оба вычисляли разные арифметические выражения для вычисления одного и того же результата.

Еще один пример, которого у меня нетКак уже упоминалось, этот подчеркивает разницу препроцессора:

#include 
int main()
{
#if true
    printf("true!\n");
#else
    printf("false!\n");
#endif
    return 0;
}

Это печатаетложный" в C и "правда" в C ++ - в C любой неопределенный макрос оценивается в 0. В C ++ существуетс 1 исключение: "правда" оценивается в 1.

 Deduplicator20 июн. 2015 г., 14:45
@DarioOO: Да, вы не правы. Переопределение ключевых слов не допускается, наказание оставлено на произвол судьбы (UB). Препроцессор, являющийся отдельной фазой компиляции, не выдерживает.
 GameDeveloper30 нояб. 2014 г., 11:45
так как "правда" является ключевым словом / допустимым значением, поэтому оно оценивается как истинное как любое "истинное значение " (так как любое положительное целое число). Вы все еще можете сделать #define true false для печати "ложный" в С ++ тоже;)
 GameDeveloper07 мая 2015 г., 14:28
Где указано, что переопределение ключевых слов является UB? препроцессор должен запускаться перед компиляцией, так что просто посмотрите на предварительно обработанный код, этот код не будет UB. Поправь меня если яя не прав
 Bryan Boettcher01 дек. 2014 г., 22:25
#define true false   ಠ_ಠ
 Ruslan07 мая 2015 г., 13:51
@DarioOO выигралт такой результат переопределения в UB?
 antred02 сент. 2014 г., 13:50
Интересно. Кто-нибудь знает обоснование этого изменения?
Решение Вопроса

Следующее, допустимое в C и C ++, (скорее всего) приведет к различным значениям вi в C и C ++:

int i = sizeof('a');

УвидетьРазмер символа («а») в C / C ++ для объяснения разницы.

Еще один изЭта статья:

#include 

int  sz = 80;

int main(void)
{
    struct sz { char c; };

    int val = sizeof(sz);      // sizeof(int) in C,
                               // sizeof(struct sz) in C++
    printf("%d\n", val);
    return 0;
}
 Mehrdad15 окт. 2012 г., 02:06
@SethCarnegie: У вас есть отличная точка зрения, но в этом яЯ сделаю исключение здесь, так как это на самом деле кажется полезным на практике. Я установил это ограничение, чтобы не получать бесполезных ответов юристов; этот, конечно, нене подпадает под эту категорию, и это кажется полезным, так что я все еще думаю, что этохороший ответ.
 Alexey Frunze15 окт. 2012 г., 01:59
Вы могли бы быть заинтересованы в чтенииЭта статья, Там должно быть больше.
 Mehrdad15 окт. 2012 г., 01:58
Определенно разве неНе ожидал этого! Я надеялся на что-то более драматичное, но это все еще полезно, спасибо. :) +1
 Seth Carnegie15 окт. 2012 г., 02:06
@ Mehrdad о, я неЯ не понимаю, что это вы задали этот вопрос. Если бы я знал, что когда я прочитал ваш первоначальный комментарий в поддержку ответа, я бы неЯ ничего не сказал. Сожалею.
 Seth Carnegie16 окт. 2012 г., 23:42
@ АндрейВихров да, я знаю. Я'я спрашиваю, если этоэто программа, которая нет, или компилятор.
 Alexey Frunze15 окт. 2012 г., 02:04
@SethCarnegie Учитывая вероятностьsizeof(int)==1Я бы небудь так уверен.
 Andrey Vihrov16 окт. 2012 г., 23:35
@SethCarnegie: Несоответствующая программа не обязательно должна работать, но она также не гарантируется.
 Seth Carnegie16 окт. 2012 г., 21:35
@ Андрей Я тоже так думал некоторое время назад и протестировал его, и он работал на GCC 4.7.1 без std, вопреки моим ожиданиям. Это ошибка в GCC?
 Alexey Frunze15 окт. 2012 г., 02:02
@SethCarnegie Хотя редко, это определенно может (добавил "более вероятный" на ответ).
 Max Barraclough05 мая 2018 г., 19:27
Отличный ответ. В Википедии есть раздел, посвященный именно этому вопросу:en.wikipedia.org/wiki/... Он упоминает различия, которые выМы указали, среди прочего, но, к сожалению, непривести множество других примеров
 Seth Carnegie15 окт. 2012 г., 02:31
+1 второй пример хорош тем, что C ++ нет требуетstruct перед именами структур.
 Martin Bonner09 янв. 2017 г., 14:52
struct sz { int i[2];}; будет означать, что C и C ++иметь производить разные значения. (Принимая во внимание, что DSP с sizeof (int) == 1,мог производить ту же стоимость).

Еще один из перечисленных в стандарте C ++:

#include 

int x[1];
int main(void) {
    struct x { int a[2]; };
    /* size of the array in C */
    /* size of the struct in C++ */
    printf("%d\n", (int)sizeof(x)); 
}
 v.oddou18 февр. 2016 г., 08:36
так вы получаете различия в отступах?
 v.oddou18 февр. 2016 г., 08:37
ах извини я понял, есть ещеx на вершине. я думал, что ты сказал "массив ".a

Эта программа печатает1 в C ++ и0 в C:

#include 
#include 

int main(void)
{
    int d = (int)(abs(0.6) + 0.5);
    printf("%d", d);
    return 0;
}

Это происходит потому, что естьdouble abs(double) перегрузка в C ++, такabs(0.6) возвращается0.6 в то время как в C он возвращает0 из-за неявного преобразования типа double в int перед вызовомint abs(int), В C вы должны использоватьfabs работать с .double

 Pavel Chikulaev02 дек. 2014 г., 04:21
И выглядит как в VS C ++, <math.h> включает материал C ++ в глобальное пространство имен, а GCC - нет. Однако не уверен, что это стандартное поведение.
 GameDeveloper02 дек. 2014 г., 14:43
нет, это не так, но многие пользователи не смогут скомпилировать код, написанный для Visual Studio, если они недобавить не включает включает в себя;) и еще хуже, естьШанс, что пользователи выигралиошибки компиляции, но странное числовое поведение из-за этого нестандартного поведения (которое может быть отключено из опций, но включено по умолчанию)
 Adrian McCarthy20 апр. 2018 г., 01:05
И хотя большинство библиотек будет определять перегрузки в обоихstd:: и глобальные пространства имен, этоВозможно, что перегрузки будут объявлены только вstd::, так что это действительно определяется реализацией. (Я все еще проголосовал, потому что этоРазница, которая происходит в реальном коде.)
 GameDeveloper30 нояб. 2014 г., 12:00
пришлось отлаживать код другого человека с этой проблемой. О, как я любил это. В любом случае, ваша программа также печатает 0 в C ++. C ++ должен использовать заголовокCMATH» см. сравнение первый возврат 0ideone.com/0tQB2G 2-й возвращается 1ideone.com/SLeANo
 M.M09 мая 2016 г., 06:25
Вторая проблема заключается в том, что, хотя стандарт C ++, кажется, говорит, что в том числе также включает в себя дополнительные перегрузки; на практике оказывается, что все основные компиляторы нет включает эти перегрузки, если форма используется.
 Pavel Chikulaev02 дек. 2014 г., 04:05
Рад / жаль слышать, что яЯ не единственный, кто находит эту разницу с помощью отладки. Только что протестированный в VS2013, пустой файл с единственным содержимым будет содержать 1, если расширение - .cpp, и 0, если расширение - .c. Выглядит как <math.h> включен косвенно в VS.
 M.M09 мая 2016 г., 06:24
Этот конкретный пример кода зависит от реализации:stdlib.h только определяетabs(int) а такжеabs(long); версияabs(double) объявленmath.h, Так что эта программа все еще может вызыватьabs(int) версия. Это'детали реализации, будь тоstdlib.h также вызываетmath.h быть включенным. (Я думаю, что это будет ошибка, еслиabs(double) были названы, но другие аспектыmath.h не были включены).
#include 

struct A {
    double a[32];
};

int main() {
    struct B {
        struct A {
            short a, b;
        } a;
    };
    printf("%d\n", sizeof(struct A));
    return 0;
}

Эта программа печатает (12832 * sizeof(double)) при компиляции с использованием компилятора C ++ и4 при компиляции с использованием компилятора C.

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

 phuclv08 авг. 2018 г., 05:31
обратите внимание, что выполучаю UBпечатьsize_t с%d
 user135455718 февр. 2016 г., 15:45
Это интересно! (Я думаю, что вы имеете в виду32*sizeof(double) а не 32 хотя :))
 wefwefa318 февр. 2016 г., 17:22
Ах, да, конечно. Исправляем это сейчас. :)
struct abort
{
    int x;
};

int main()
{
    abort();
    return 0;
}

Возвращает с кодом выхода 0 в C ++ или 3 в C.

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

struct exit
{
    int x;
};

int main()
{
    struct exit code;
    code.x=1;

    exit(code);

    return 0;
}

VC ++ 2005 отказался компилировать это в режиме C ++, хотя жаловался на то, как »код выхода " был переопределен. (Я думаю, что это ошибка компилятора, если я нея вдруг забыл, как программировать.) Он завершился с кодом завершения процесса, равным 1, хотя и скомпилирован как C.

 immibis25 мар. 2015 г., 09:57
exit(code) является действительным объявлением переменнойcode типаexit, по-видимому. (Увидеть "самый неприятный разбор ", что является другим, но похожим вопросом).
 Sean24 февр. 2009 г., 03:55
Ваш второй пример с использованием exit, неt компилируется на gcc или g ++, к сожалению. Это'хорошая идея, хотя.

Дон»Забудьте о разнице между глобальными пространствами имен C и C ++. Предположим, у вас естьfoo.cpp

#include 

void foo(int r)
{
  printf("I am C++\n");
}

иfoo2.c

#include 

void foo(int r)
{
  printf("I am C\n");
}

Теперь предположим, что у вас естьmain.c а такжеmain.cpp которые оба выглядят так:

extern void foo(int);

int main(void)
{
  foo(1);
  return 0;
}

При компиляции как C ++ он будет использовать символ в глобальном пространстве имен C ++; в C он будет использовать C one:

$ diff main.cpp main.c
$ gcc -o test main.cpp foo.cpp foo2.c
$ ./test 
I am C++
$ gcc -o test main.c foo.cpp foo2.c
$ ./test 
I am C
 skyking21 авг. 2015 г., 09:25
Упорядочивание имен не является частью спецификации C ++. Это запрещено в C?
 Mehrdad17 окт. 2014 г., 11:31
Вы имеете в виду спецификацию связей?
 GameDeveloper30 нояб. 2014 г., 11:53
искажение имени. Имена C ++ имеют префиксы и суффиксы, в то время как C не
 M.M09 мая 2016 г., 05:49
Это неопределенное поведение (множественное определениеfoo). Есть не отдельные "глобальные пространства имен ".

Это касается lvalues и rvalues в C и C ++.

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

int a = 5;
a++ = 2;  /* error: lvalue required as left operand of assignment */
++a = 2;  /* error: lvalue required as left operand of assignment */

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

int a = 5;
a++ = 2;  // error: lvalue required as left operand of assignment
++a = 2;  // No error: a gets assigned to 2!

Теперь, почему это так? Постинкремент увеличивает переменную и возвращает переменную такой, какой она быладо увеличение произошло. На самом деле это просто ценность. Прежнее значение переменной a копируется в регистр как временное, а затем увеличивается на a. Но прежнее значение a возвращается выражением, это rvalue. Он больше не представляет текущее содержимое переменной.

Предварительное увеличение сначала увеличивает переменную, а затем возвращает переменную,после увеличение произошло. В этом случае нам не нужно сохранять старое значение переменной во временном регистре. Мы просто получаем новое значение переменной после ее увеличения. Таким образом, предварительное приращение возвращает lvalue, оно возвращает саму переменную a. Мы можем использовать присвоение этого lvalue чему-то другому, это похоже на следующее утверждение. Это неявное преобразование lvalue в rvalue.

int x = a;
int x = ++a;

Поскольку предварительное приращение возвращает lvalue, мы также можем присвоить ему что-то. Следующие два утверждения идентичны. Во втором присваивании сначала увеличивается значение a, а затем его новое значение перезаписывается на 2.

int a;
a = 2;
++a = 2;  // Valid in C++.
 o11c27 нояб. 2018 г., 07:25
Там'нет "действует в С " Вот.

Другаяsizeof ловушка: логические выражения.

#include 
int main() {
    printf("%d\n", (int)sizeof !0);
}

Это равноsizeof(int) в C, потому что выражение имеет типint, но обычно 1 в C ++ (хотя этоне обязательно быть). На практике они почти всегда разные.

 EvilTeach19 апр. 2017 г., 18:41
!! является оператором преобразования int в логическое значение :)
 Alexey Frunze15 окт. 2012 г., 16:15
Один! должно быть достаточно для.bool
 Galaxy22 июн. 2018 г., 00:24
sizeof(0) является4 в обоих C и C ++, потому что0 целое числоsizeof(!0) является4 в С и1 в C ++. Логическое НЕ действует на операнды типа bool. Если значение int0 оно неявно преобразуется вfalse (bool rvalue), затем он переворачивается, в результате чегоtrue, И то и другоеtrue а такжеfalse являются значениями bool в C ++ иsizeof(bool) является1, Однако в C!0 оценивает1, который является значением типа int. Язык программирования C не имеет типа данных bool по умолчанию.

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

...
int a = 4 //* */ 2
        +2;
printf("%i\n",a);
...
 Jonathan Leffler24 февр. 2009 г., 01:20
Чтобы'только в компиляторах C89, а не современных ...

Вот пример, который использует разницу между вызовами функций и объявлениями объектов в C и C ++, а также тот факт, что C90 позволяет вызывать необъявленные функции:

#include 

struct f { int x; };

int main() {
    f();
}

int f() {
    return printf("hello");
}

В C ++ это ничего не печатает, потому что временныйf создан и уничтожен, но в C90 он напечатаетhello потому что функции могут быть вызваны без объявления.

В случае, если вы задавались вопросом о названииf будучи использованным дважды, стандарты C и C ++ явно разрешают это, и для создания объекта вы должны сказатьstruct f для устранения неоднозначности, если вы хотите структуру, или оставитьstruct если вы хотите функцию.

 Peter Cordes23 дек. 2016 г., 03:57
Интересный факт: чтобы gcc фактически отклонил этот код как C, вам нужно-std=c99 -pedantic-errors, В противном случае он компилируется только с предупреждением о неявном объявлении, даже с-std=c11 -pedantic, Смотрите это напроводник компилятора Godbolt,документы компилятора просто поговорим о стандарте ISOтребующий диагностики ».
 Seth Carnegie03 янв. 2013 г., 19:13
@muntoo Нет, самый неприятный анализ - когда программист пытается объявить переменную типаvector и пишетvector v();, но компилятор воспринимает это как объявление функции, не принимающей параметров, возвращающихvector, Нетt имя для того, что я написал AFAIK, просто комбо C требуетstruct и C ++ нет, и C разрешает вызовы функций без предыдущих объявлений, а C ++ нет.
 Martin Bonner09 авг. 2018 г., 16:26
@ user529758 - Они вполне могут быть компиляторами C99. C99, который обнаруживает необъявленные идентификаторы, должен рассматривать его как синтаксическую ошибку и должен "выбрасывать диагностику; этоне требуется, чтобы не скомпилировать файл.
 Deduplicator20 июн. 2015 г., 14:39
Кроме того, C не позволяетstructбез какого-либо члена, эторасширение
 Sogartar15 окт. 2012 г., 13:11
Строго говоря, в C это не скомпилируется, потому что объявление "int f () " после определенияint main () " :)
 user52975819 янв. 2014 г., 23:25
@AlexB Не в C99 и C11.
 krichard15 окт. 2012 г., 12:44
привычкаint f() попасть в компилятор?
 user52975819 янв. 2014 г., 23:26
@jrajav Тогда это не компиляторы C99. Компилятор C99 обнаруживает необъявленные идентификаторы как синтаксическую ошибку. Компилятор, который неЭто может быть либо компилятор C89, либо предстандартный, либо другой тип несовместимого компилятора.
 jrajav15 окт. 2012 г., 13:29
@ Согартар, правда?codepad.org/STSQlUhh Компиляторы C99 предупредят вас, но ониЯ все еще позволю тебе скомпилировать это.
 Alex B20 янв. 2014 г., 12:13
@ H2CO3 OP отметил, что C90 является приемлемой базой, поэтомувсе еще в силе. Кроме того, C89 являетсяеще широко распространенный.
 Alex B15 окт. 2012 г., 13:48
@Sogartar в функциях C допускается неявно объявлять.

С90 против С ++ 11 (int противdouble):

#include 

int main()
{
  auto j = 1.5;
  printf("%d", (int)sizeof(j));
  return 0;
}

В Сauto означает локальную переменную. В С90 это вышлоМожно опустить переменную или тип функции. По умолчаниюint, В С ++ 11auto означает нечто совершенно иное, он говорит компилятору выводить тип переменной из значения, использованного для ее инициализации.

 R..15 окт. 2012 г., 04:42
С11 не имеет неявного.int
 Mehrdad15 окт. 2012 г., 03:48
@SethCarnegie: Да, этокласс хранения; Это'Что происходит по умолчанию, когда вы его опускаете, поэтому никто не использовал его, и они изменили его значение. Я думаю, что этоint по умолчанию. Это умно! +1
 Keith Thompson15 окт. 2012 г., 04:27
Можно утверждать, что этоне правильное сравнение; вы'сравнивая устаревшую версию C с текущей версией C ++.
 Jim Balter15 окт. 2012 г., 04:42
@KeithThompson Ах, я думаю, вы имеете в виду выводint, Тем не менее, в реальном мире, где есть тонны унаследованного кода, а лидер рынка до сих порЯ реализовал C99 и не собираюсь этого делать.Устаревшая версия C " Абсурд ".
 btown15 окт. 2012 г., 17:28
Каждая переменная ДОЛЖНА иметь явный класс хранения. С уважением, высшее руководство. "
 Seth Carnegie15 окт. 2012 г., 03:45
С90 имеет?auto
 Jim Balter15 окт. 2012 г., 04:37
@KeithThompson А? C11 до сих пор имеет auto, который был в C с момента его зачатия.
 detunized15 окт. 2012 г., 03:47
#include 

int main(void)
{
    printf("%d\n", (int)sizeof('a'));
    return 0;
}

В C это печатает независимо от значенияsizeof(int) находится в текущей системе, которая обычно4 в большинстве систем, обычно используемых сегодня.

В C ++ это должно вывести 1.

 Sean24 февр. 2009 г., 00:29
Да, я был на самом деле знаком с этим трюком, потому что это «с» это int в C и char в C ++, но это 'все еще хорошо, чтобы это было перечислено здесь.
 Destructor09 мая 2016 г., 07:04
@R ..: Смотри, он использует явное приведение кИНТ , Это хорошо определенное поведение.
 Destructor11 мая 2016 г., 19:55
@KenWayneVanderLinde: о, правда? Я не'не замечаю, что
 Martin Beckett24 февр. 2009 г., 00:32
Это сделало бы интересным вопрос для интервью - особенно для людей, которые ставят эксперта по c / c ++ в свои резюме.
 Ken Wayne VanderLinde11 мая 2016 г., 19:49
@ Разрушитель А тыЗаметьте, что приведение было добавлено после того, как комментарий был сделан.
 Windows programmer24 февр. 2009 г., 01:06
В C значение определяется реализацией, а 1 - возможность. (В C ++ он должен печатать 1, как указано.)
 R..27 февр. 2014 г., 21:49
На самом деле он имеет неопределенное поведение в обоих случаях.%d неправильный спецификатор формата для.size_t
 Dana the Sane24 февр. 2009 г., 00:37
Отчасти закулисный, хотя. Вся цель sizeof в том, чтобы вы неНе нужно точно знать, насколько велик тип.
 Adam Rosenfield27 февр. 2014 г., 23:00
@R ..: Достаточно справедливо, хотя этоСуть этого примера. Я изменил это так, чтобыбольше не так и такдействительный C89, так как C89 не имеетz модификатор длины.

Ваш ответ на вопрос