Включая заголовки C в пространство имен C ++ - это стандартное поведение?

18

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

namespace AAA {
    extern "C" {
        #include "sqlite3.h"     // C API.
    }
}

И тогда все типы и функции C будут помещены в пространство имен. Более интересно, что все связанные функции C также работают! Я также обнаружил, что это может вызвать некоторые проблемы с препроцессором, но, кроме того, кажется, что это работает очень хорошо.

Это стандартное поведение? (Я использую Clang 3.x) Если это так, то каково название этой функции и где я могу найти эту функцию, упомянутую в стандарте?

    
задан Eonil 03.02.2014 в 07:52
источник
  • #include в основном просто копировать и вставлять. Таким образом, до тех пор, пока то, что находится в этом файле, легально вписывается в пространство имен, это прекрасно по сравнению с компилятором. –  Brandin 03.02.2014 в 07:55
  • Опять же, макрос - это просто замена текста –  texasbruce 03.02.2014 в 07:59
  • также вы можете использовать автономную утилиту cpp или флаг -E для компилятора (как GCC, так и CLang), чтобы получить «обработанные источники» (т. е. все введенные слова включены, все макросы и #ifdefs разрешены). Поэтому, если препроцессор дает действительный C ++, пусть будет так. Если это не так, вам нужно как-то справиться с этим –  user3159253 03.02.2014 в 08:01
  • Я обновил вопрос, чтобы добавить пропущенную точку. Все связанные функции также хорошо работают. –  Eonil 03.02.2014 в 08:08
  • @ Эноил, почему бы и нет? Они находятся во внешнем блоке «С», поэтому их связь - это нестандартный материал C. –  casey 03.02.2014 в 15:20

2 ответа

9

Вы можете даже делать странные вещи, такие как

//test.c
int
    #include "main.h"
{
    return 1;
}

//main.h
main(void)

Макросы препроцессора расширяются до того, как будет выполнена любая проверка синтаксиса. Вышеприведенный пример будет расширяться до

int
main(void)
{
    return 1;
}

, который является юридическим кодом. Хотя вам действительно следует избегать таких примеров, бывают случаи, когда включение в другой элемент весьма полезно. В вашем вопросе это зависит от того, как имена искажаются во время компиляции. Если все определения в вашем файле заголовка объявлены с помощью extern "C" , имена будут искаться в объектном файле, но это не так, если объектный файл, содержащий реализацию, не использует то же пространство имен, что и определение в коде потребления и не объявляет его extern "C" .

    
ответ дан urzeit 03.02.2014 в 08:06
4
  

Это стандартное поведение?

Да - поведение поддерживается стандартом, поскольку компилятор C ++ на самом деле не имеет понятия «C» в сравнении с «C ++», за исключением случаев, когда extern "C" используется для запрета манипулирования пространства имен.

Следствием не подавления искажения является то, что вы можете получить ошибки «неразрешенных символов» во время ссылки, если вы попытаетесь связать с библиотекой C, определяющей символы вне строки ( extern variables, functions) в заголовке.

  

Если это [стандартная функция], как называется эта функция, и где я могу найти эту функцию, указанную в стандарте?

Это просто следствие того, как работает #include , которое определено в 16.2. Включение исходного файла [cpp.include], в решающей степени:

  

[a #include ] вызывает замену этой директивы всем содержимым исходного файла, идентифицированного указанной последовательностью между «разделителями».

Итак, что бы ни случилось с заголовком «С», точно так же, как если бы окружающие команды namespace / extern и фигурные скобки существовали в верхней и нижней части файла заголовка ... к тому времени, когда следующий этап компиляция начинает непрактично, откуда исходил исходный код (за исключением отображения сообщений об ошибках, которые должным образом относятся к исходному файлу).

    
ответ дан Tony Delroy 03.02.2014 в 08:07