Я просмотрел некоторый код и заметил, что соглашение заключалось в том, чтобы переключать такие типы указателей, как
SomeStruct*
в
typedef SomeStruct* pSomeStruct;
Есть ли в этом заслуга?
Я просмотрел некоторый код и заметил, что соглашение заключалось в том, чтобы переключать такие типы указателей, как
SomeStruct*
в
typedef SomeStruct* pSomeStruct;
Есть ли в этом заслуга?
Это может быть уместно, когда сам указатель можно рассматривать как «черный ящик», то есть фрагмент данных, внутреннее представление которого не должно иметь отношения к коду.
По сути, если ваш код никогда не разыменовывает указатель, и вы просто передаете его функциям API (иногда по ссылке), тогда typedef не только уменьшает количество *
s в вашем коде, но также предлагает программисту, что указатель действительно не должен вмешиваться.
Это также упрощает изменение API в будущем, если возникнет такая необходимость. Например, если вы перейдете на использование идентификатора, а не указателя (или наоборот), существующий код не сломается, потому что указатель никогда не должен был быть разыменован в первую очередь.
FILE *
совершенно ненужным. Было бы неплохо, если бы они так давно напечатали.
- person Matt Joiner; 09.06.2010
typedef
-указатель может значительно повысить удобочитаемость. Представьте, что у вас есть std::map<int, std::map<std::string, std::vector<int> > >
в качестве переменной. Если вам нужно определить множество таких переменных в разных местах вашего кода, использование красивого typedef
может сделать работу, а также чтение кода более приятным занятием.
- person rbaleksandar; 30.05.2016
FILE*
не был определен по типу как непрозрачный указатель, заключается в том, чтобы позволить макросам, таким как getc()
и putc()
, напрямую манипулировать структурой FILE и избежать накладных расходов на вызов функции в большинстве случаев.
- person chqrlie; 18.08.2016
struct XYZ; typedef struct XYZ* Handle;
- если реализация требуется несколько единиц компиляции, он может быть определен в отдельном закрытом заголовке ...
- person Aconcagua; 11.12.2018
typedef
непрозрачного указателя. Непрозрачные структуры C: как их объявлять? а>
- person Gabriel Staples; 23.10.2020
Не по моему опыту. Скрытие "*
" затрудняет чтение кода.
Device
, а вы typedef
, это Device_Ptr
(вместо того, чтобы использовать Device *
) или что-то подобное, он вполне читаем. Я вижу много хорошо продуманных и довольно больших библиотек, которые это делают. Если вы добавляете шаблоны, особенно в C ++, это избавляет ваши пальцы от необходимости печатать.
- person rbaleksandar; 15.02.2017
myTypePtr
или myTypeRef
над этой звездой в любой день. :П
- person Christoffer Bubach; 30.06.2020
Единственный раз, когда я использую указатель внутри typedef, - это когда имею дело с указателями на функции:
typedef void (*SigCatcher(int, void (*)(int)))(int);
typedef void (*SigCatcher)(int);
SigCatcher old = signal(SIGINT, SIG_IGN);
В противном случае я считаю их больше сбивающими с толку, чем полезными.
signal()
, а не для улавливателя сигналов. Это можно сделать более понятным (используя исправленный тип SigCatcher
выше), написав:
typedef SigCatcher (*SignalFunction)(int, SigCatcher);
Или, чтобы объявить функцию signal()
:
extern SigCatcher signal(int, SigCatcher);
То есть SignalFunction
- это указатель на функцию, которая принимает два аргумента (int
и SigCatcher
) и возвращает SigCatcher
. А сама signal()
является функцией, которая принимает два аргумента (int
и SigCatcher
) и возвращает SigCatcher
.
sig_t
, совпадает с моим SigCatcher
, и да, это значительно упрощает объявление signal()
.
- person Jonathan Leffler; 07.11.2010
Это может помочь вам избежать некоторых ошибок. Например, в следующем коде:
int* pointer1, pointer2;
Указатель2 не является int *, это просто int. Но с typedef этого не произойдет:
typedef int* pInt;
pInt pointer1, pointer2;
Теперь они оба int *.
int *p1 = NULL, *p2 = NULL;
- person Matt Joiner; 09.06.2010
*
не имеет значения.
- person Lundin; 03.12.2015
Мой ответ - однозначное «Нет».
Почему?
Во-первых, вы просто меняете один символ *
на другой отдельный символ p
. Это нулевой прирост. Одно это должно удерживать вас от этого, потому что делать лишние бессмысленные вещи всегда плохо.
Во-вторых, и это важная причина, *
несет значение, которое не следует скрывать. Если я передам что-то такой функции
void foo(SomeType bar);
void baz() {
SomeType myBar = getSomeType();
foo(myBar);
}
Я не ожидаю, что значение myBar
изменится, если передать его foo()
. В конце концов, я передаю по значению, так что foo()
когда-либо видит только копию myBar
, верно? Не тогда, когда псевдоним SomeType
означает какой-то указатель!
Это применимо как к указателям C, так и к интеллектуальным указателям C ++: если вы скроете тот факт, что они являются указателями для ваших пользователей, вы создадите беспорядок, в котором нет необходимости. Поэтому, пожалуйста, не используйте псевдонимы для своих указателей.
(Я считаю, что привычка определять типы указателей - это просто ошибочная попытка скрыть, сколько звездочек у человека, как у программиста http://wiki.c2.com/?ThreeStarProgrammer.)
void *vp=/*...*/; foo(vp);
или foo(0);
. (Определения типов для перечислений и определения числовых типов для вещей, которые никогда не должны отображаться как числа, имеют аналогичные проблемы).
- person PSkocik; 11.11.2018
Это вопрос стиля. Вы очень часто видите такой код в заголовочных файлах Windows. Хотя они, как правило, предпочитают версию в верхнем регистре вместо строчной буквы p.
Лично я избегаю этого использования typedef. Намного понятнее, если пользователь явно скажет, что ему нужен Foo *, чем PFoo. Typedef в наши дни лучше всего подходят для чтения в STL :)
typedef stl::map<stl::wstring,CAdapt<CComPtr<IFoo>> NameToFooMap;
Это (как и многие ответы) зависит.
В C это очень распространено, поскольку вы пытаетесь замаскировать объект как указатель. Вы пытаетесь намекнуть, что это объект, которым манипулируют все ваши функции (мы знаем, что это указатель внизу, но он представляет объект, которым вы управляете).
MYDB db = MYDBcreateDB("Plop://djdjdjjdjd");
MYDBDoSomthingWithDB(db,5,6,7);
CallLocalFuc(db); // if db is not a pointer things could be complicated.
MYDBdestroyDB(db);
Под MYDB, вероятно, находится указатель на какой-то объект.
В C ++ это больше не требуется.
В основном потому, что мы можем передавать информацию по ссылке, а методы включены в объявление класса.
MyDB db("Plop://djdjdjjdjd");
db.DoSomthingWithDB(5,6,7);
CallLocalFuc(db); // This time we can call be reference.
db.destroyDB(); // Or let the destructor handle it.
No.
Это сделает вашу жизнь несчастной, как только вы смешаете ее с const
typedef foo *fooptr;
const fooptr bar1;
const foo *bar2
bar1
и bar2
одного типа?
И да, я просто цитирую Гуру Херба Саттера. Она говорила много правды. ;)
-- Редактировать --
Добавление ссылки на цитируемую статью.
http://www.drdobbs.com/conversationsa-midsummer-nights-madness/184403835
Typedef используется, чтобы сделать код более читаемым, но использование указателя в качестве typedef вызовет путаницу. Лучше избегать указателей typedef.
Обсуждение проводится при условии, что интересующий язык - C. Разветвления для C ++ не рассматривались.
Вопрос Размер структуры, которая определяется как указатель, поднимает интересный побочный свет при использовании typedef
для указателей (структуры).
Рассмотрим определение бетонного (непрозрачного) типа структуры без тегов:
typedef struct { int field1; double field2; } *Information;
Детали участников совершенно не касаются этого обсуждения; все, что имеет значение, это то, что это не непрозрачный тип, такой как typedef struct tag *tag;
(и вы не можете определить такие непрозрачные типы с помощью typedef
без тега).
Возникает вопрос: «Как узнать размер этой структуры»?
Краткий ответ: «только через переменную типа». Нет тега для использования с sizeof(struct tag)
. Вы не можете использовать, например, , а sizeof(*Information)
sizeof(Information *)
- это размер указателя на тип указателя, а не размер типа структуры.
Фактически, если вы хотите выделить такую структуру, вы не можете создать ее, кроме как с помощью динамического распределения (или суррогатных методов, имитирующих динамическое распределение). Невозможно создать локальную переменную типа структуры, указатели которой называются Information
, также нет способа создать переменную области видимости файла (глобальную или static
) типа структуры, а также нет способа встроить такую структуру (в отличие от указателя на такую структуру) в другую структуру или тип объединения.
Вы можете - должны - написать:
Information info = malloc(sizeof(*info));
Помимо того, что указатель скрыт в typedef
, это хорошая практика - если тип info
изменится, распределение размера останется точным. Но в этом случае это также единственный способ получить размер структуры и выделить структуру. И нет другого способа создать экземпляр структуры.
Это зависит от ваших целей.
Это не непрозрачный тип - детали структуры должны быть определены, когда тип указателя typedef
'd.
Это тип, который можно использовать только с динамическим распределением памяти.
Это безымянный тип. Указатель на тип структуры имеет имя, а сам тип структуры - нет.
Если вы хотите принудительно использовать динамическое распределение, это, кажется, способ сделать это.
Однако в целом это скорее вызовет замешательство и тревогу, чем просветление.
В общем, использование typedef
для определения указателя на тип структуры без тегов - плохая идея.
Если вы сделаете это, вы не сможете создавать STL-контейнеры const pSomeStruct, поскольку компилятор читает:
list<const pSomeStruct> structs;
as
list<SomeStruct * const> structs;
который не является легальным контейнером STL, поскольку элементы не могут быть присвоены.
См. Этот вопрос.
list<const ordinary_type>
, так как это все равно не сработает, так что нет никакой путаницы.
- person ; 21.04.2014
ordinary_type
. list<const SomeStruct*>
вполне допустим, поскольку const SomeStruct*
является CopyAssignable.
- person Dan Hook; 22.04.2014
Win32 API делает это практически с каждой структурой (если не со всеми).
POINT => *LPPOINT
WNDCLASSEX => *LPWNDCLASSEX
RECT => *LPRECT
PRINT_INFO_2 => *LPPRINT_INFO_2
Приятно, что это единообразно, но, на мой взгляд, элегантности это не добавляет.
LP
означает длинный указатель, а сокращенная запись LPPOINT ptr;
была не чем иным, как удобным сокращением для POINT FAR *ptr;
, FAR
, расширяющимся до far
, а затем до __far
. Все это довольно неэлегантно, но раньше было еще хуже.
- person chqrlie; 18.08.2016
Цель typedef - скрыть детали реализации, но определение типа свойства указателя скрывает слишком многое и затрудняет чтение / понимание кода. Так что, пожалуйста, не делай этого.
Если вы хотите скрыть детали реализации (что часто бывает полезно), не скрывайте часть указателя. Возьмем, к примеру, прототип стандартного FILE
интерфейса:
FILE *fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, FILE *stream);
здесь fopen возвращает указатель на некоторую структуру FILE
(детали реализации которой вы не знаете). Возможно, FILE
не такой уж хороший пример, потому что в этом случае он мог работать с каким-то типом pFILE, который скрывал тот факт, что это указатель.
pFILE fopen(const char *filename, const char *mode);
char *fgets(char *s, int size, pFILE stream);
Однако это сработает только потому, что вы никогда не возитесь с контентом, на который прямо указывается. По моему опыту, в тот момент, когда вы вводите какой-то указатель, который вы где-то модифицируете, становится очень трудно читать.
Некоторое время назад я бы ответил «нет» на этот вопрос. Теперь, с появлением интеллектуальных указателей, указатели больше не всегда обозначаются звездочкой '*'. Таким образом, нет ничего очевидного в том, является ли тип указателем или нет.
Итак, теперь я бы сказал: указатели typedef - это нормально, если четко указано, что это «тип указателя». Это означает, что вы должны использовать префикс / суффикс специально для этого. Нет, например, «p» не является достаточным префиксом. Я бы, наверное, выбрал "ptr".