*
и **
имеют специальное использование в списке аргументов функции. *
подразумевает, что аргумент представляет собой список, а **
подразумевает, что аргумент является словарем. Это позволяет функциям принимать произвольное количество аргументов
Нет смысла анализировать поведение typedef
на основе текстовой замены. Typedef-имена не являются макросами, они не заменяются текстовыми.
Как вы отметили себя
typedef CHARS const CPTR;
- это то же самое, что и
typedef const CHARS CPTR;
по той же причине, почему
typedef const int CI;
имеет то же значение, что и
typedef int const CI;
Typedef-name не определяет новые типы (только псевдонимы для существующих), но они «атомарны» в том смысле, что любые квалификаторы (например, const
) применяются на самом верхнем уровне, т. е. применяются к типу whole , скрытому за именем typedef. После того как вы определили имя typedef, вы не можете «ввести» в него классификатор, чтобы он изменял любые более глубокие уровни типа.
Typedef не является простой текстовой заменой.
typedef const CHARS CPTR;
Означает: «Тип CPTR будет состоять из const CHARS». Но CHARS - это тип указателя на символ, так что это говорит о том, что тип CPTR будет типом const-указателя-символа. Это не соответствует тому, что вы видите при простой замене.
Другими словами,
typedef char * CHARS;
является не таким же, как
#define CHARS char *
Синтаксис typedef похож на объявление переменной, за исключением того, что вместо объявления имени цели в качестве переменной он объявляет его как новое имя типа, которое может быть использовано для объявления переменных типа, которые переменная будет без typedef.
Вот простой способ выяснить, что объявляет typedef:
typedef
. Теперь у вас будет объявление переменной. const CHARS CPTR;
typeof()
, который делает именно это и очень полезен). Вызовите этот тип T. В этом случае указатель константы на (непостоянный) символ. typedef
. Теперь вы объявляете новый тип (CPTR
), который является точно таким же типом, что и T, постоянным указателем на (непостоянный) char.