Пространства имен в c ++ и c - PullRequest
10 голосов
/ 29 сентября 2011

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

#include <stdlib.h>

typedef struct foo { int foo; } foo;

foo * alloc_foo () {
   return (struct foo*) malloc(sizeof(foo));
}   

struct foo * alloc_struct_foo () {
   return (foo*) malloc(sizeof(struct foo));
}   


foo * make_foo1 (int val) {
   foo * foo = alloc_struct_foo (); 
   foo->foo = 0;
   return foo;
}

struct foo * make_foo2 (int val) {
   struct foo * foo = alloc_foo();
   foo->foo = 0;
   return foo;
}

Что делаетэтот законный и недвусмысленный в C раздел 6.2.3 стандарта C:

6.2.3 Пространства имен идентификаторов
Если в любой точке видны более одного объявления определенного идентификатораединица перевода, синтаксический контекст устраняет неоднозначность использования, которое относится к различным объектам.Таким образом, существуют отдельные пространства имен для различных категорий идентификаторов (имена меток; теги структур, объединений и перечислений; членов структур или объединений и обычных идентификаторов).

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

Добавьте следующее, и код не компилируется:

int foo (foo * ptr) {
   return ++ptr->foo;
}   

Итак, два вопроса, один из которых касается C и C ++, а другой - C ++.

  • C / C ++ вопрос: почему я не могу определить функцию foo?
    Кажется, я должен быть в состоянии определить функцию foo;Имена функций и имена переменных являются «обычными идентификаторами».Но если я добавлю этот последний кусочек кода, я получу error: redefinition of 'foo' as different kind of symbol.
    Вопрос: foo * foo; совершенно законно, так почему же не int foo (foo*); законно?

  • Вопрос C ++: как это вообще работает в C ++?
    Значение «пространства имен» приобретает в C ++ совсем другое значение, чем в C. Я не могу найти в стандарте C ++ ничего такого, что говорит о CКонцепция пространств имен, что делает вышеуказанное легальным в C.
    Вопрос: Что делает это легальным в C ++ (предпочтительны глава и стих)?

Ответы [ 4 ]

8 голосов
/ 29 сентября 2011

foo * foo; совершенно законно, так почему не int foo (foo*); законно?

Потому что уже есть тип с именем foo в том же контексте объявления, что и ваша функция. Вы не можете иметь тип и функцию с одинаковым именем в одной и той же области видимости.

Как это работает вообще в C ++?

Потому что вам разрешено скрывать имена во вложенных областях. Когда вы объявляете foo * foo, первый foo относится к типу. Второй foo объявляет переменную - в этот момент тип foo скрыт. Попробуйте объявить foo * baz после foo * foo, оно должно завершиться неудачей.

struct foo {};

void test() {
   foo * foo; // first `foo` is the type, second `foo` is the variable
   foo * baz; // first `foo` is the variable
}
1 голос
/ 29 сентября 2011

В C ++ 11 3.3.1 / 4 говорит, что в декларативной области все объявления имени должны ссылаться на одну и ту же сущность (или набор перегрузки). Есть исключение, которое позволяет вам использовать имя класса для набора имен функций (поэтому foo() скрывает class foo), но это не применяется, если у вас есть typedef (что вы делаете).

Попробуйте это с typedef struct foo foo, опущенным в C ++.

0 голосов
/ 29 сентября 2011

Поскольку уже есть функция foo(), это конструкция по умолчанию для struct foo

typedef struct foo 
{ 
int a; 
foo(int val)
:a(val) 
{}
} foo;


int foo(int value)
{
  cout << value <<endl;
}

void main()
{
   foo foovar = foo(50); // constructor foo or function foo?
}

В C. нет таких вещей, как конструкторы.

Редактировать специально для Алана Стоукса:

typedef struct foo
    { 
    int a; 
    foo(int val, double val2)
    :a(val) 
    {
      cout << val2 << endl;
    }
    } foo;


    int foo(int value, double val2)
    {
      cout << value << val2 << endl;
    }

    void main()
    {
       some_random_func(foo(50, 1.0)); // constructor foo or function foo?
    }
0 голосов
/ 29 сентября 2011

Это также не работает в C ++ ... проблема в том, что препроцессор для gcc / g ++ ищет __cplusplus, а не cplusplus. Поэтому вы препроцессор заявления

#if defined FOO && ! defined cplusplus
#undef FOO
#endif

не работают правильно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...