Определение типа еще является просто строковой заменой в коде или somethings?

Мне было любопытно знать, как точно определение типа работает.

typedef struct example identifier;

identifier x;

В вышеупомянутом операторе 'идентификатор' просто заменен (somethings как строковая замена) с 'примером структуры' в коде? Если не, что определение типа делает здесь?

просветите!

8
задан KedarX 16 July 2010 в 08:47
поделиться

8 ответов

Нет, это не замена строки - это были бы макросы. Он создает псевдоним для типа.

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

typedef char *String_t;
#define String_d char *
String_t s1, s2;
String_d s3, s4;

s1, s2 и s3 объявлены как char *, но s4 объявлен как char, что, вероятно, не является намерением.

32
ответ дан 5 December 2019 в 04:36
поделиться

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

И в C, и в C++ идентификаторы, определяемые пользователем, хранятся в разных пространствах имен (не в смысле C++, а в смысле идентификаторов). Когда вы используете ключевое слово typedef, вы создаете псевдоним для типа в глобальном пространстве имен, где находятся функции.

// C/C++
struct test {};
void test( struct test x ) {} // ok, no collision

// C/C++
typedef struct test {} test; // test is now both in types and global spaces
//void test() {}       // compiler error: test is a typedef, cannot be redefined

Небольшое отличие здесь в том, что в C++ компилятор сначала будет искать в глобальном пространстве имен, а если не найдет там, то будет искать и в пространстве имен типов:

// C
struct test {};
//void f( test t );      // error, test is not defined in the global namespace
void f( struct test t ); // ok, we are telling the compiler where to look

// C++
struct test {};
void f( test t );        // ok, no test defined in the global name space, 
                         // the compiler looks in the types name space
void g( struct test t ); // also ok, even if 'struct' not needed here.

Но это не означает, что два пространства имен слиты, только то, что поиск будет вестись в обоих местах.

5
ответ дан 5 December 2019 в 04:36
поделиться

А typedef вводит синоним для типов. Это не простая замена строки, как показано ниже:

typedef int* int_ptr;
const int* a;    // pointer to const int
const int_ptr b; // const pointer to int

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

9
ответ дан 5 December 2019 в 04:36
поделиться

Одним из важных отличий является то, что typedef имеют область видимости .

Ниже приводится общая идиома.

class Foo: public Bar 
{
  private:
   typedef Bar inherited;

  public:
    Foo(int x) : inherited(x) {};  // preferred to 'Bar(x)' 
}

Часто определение конструктора содержится в файле .cpp с объявлением в заголовке. Если вы используете Foo (int x): Bar (x) , есть большая вероятность, что вы забудете обновить конструктор, если измените иерархию классов так, чтобы Foo-> Wibble-> Bar вместо Foo- > Бар. Лично я рекомендую добавлять «унаследованный» typedef к каждому подклассу.

Подробнее см. Здесь: Использование "super" в C ++

2
ответ дан 5 December 2019 в 04:36
поделиться

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

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

Можно считать, что компилятор выполняет аналогичную "работу", как если бы вы объявили struct. Там есть определение, и компилятор превращает его в тип в своем списке типов.

0
ответ дан 5 December 2019 в 04:36
поделиться

С помощью typedef вы создаете псевдоним. Компилятор заменяет псевдоним правильным кодом.

Если вы напишете:

typedef int company_id;
company_id mycompany = 100;

Компилятор получит:

int mycompany = 100;
0
ответ дан 5 December 2019 в 04:36
поделиться

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

typedef int three_by_three[3][3];

three_by_three* foo();

А вот как это можно сделать без typedef:

int (*bar())[3][3];

Обратите внимание, что эта подпись совсем не похожа на первую версию с примененной «заменой строки».

Если бы синтаксис декларатора C не был таким уродливым (Страуструп: «Я считаю синтаксис декларатора C неудачным экспериментом»), typedefs, вероятно, не использовались бы так часто, как сейчас.

0
ответ дан 5 December 2019 в 04:36
поделиться

Typedef - это ярлык, который создает новое имя для (обычно сложного) типа. Его назначение более узкое, чем замена строк в препроцессоре. Таким образом, он менее подвержен ошибкам, чем определения препроцессора (которые разбираются рекурсивно).

0
ответ дан 5 December 2019 в 04:36
поделиться