Декларация и инициализация
Наброски перевода полного списка из http://c-faq.com/questions.html1.1
Q: Какой тип целочисленной переменной использовать ? A: Если могут потребоваться большие числа, (больше 32767 или меньше -32767), используйте тип long. Если нет, и важна экономия памяти (большие массивы или много структур), используйте short. Во всех остальных случаях используйте int. Если важно точно определить момент переполнения и/или знак числа не имеет значения, используйте соответствующий тип unsigned. (Но будьте внимательны при совместном использовании типов signed и unsigned в выражениях). Похожие соображения применимы при выборе между float и double. Хотя тип char или unsigned char может использоваться как целочисленный тип наименьшего размера, от этого больше вреда, чем пользы из-за непредсказуемых перемен знака и возрастающего размера программы. Эти правила, очевидно, не применимы к адресам переменных, поскольку адрес должен иметь совершенно определенный тип. Если необходимо объявить переменную определенного размера, (единственной причиной тут может быть попытка удовлетворить внешним требованиям к организации памяти; см.,кроме того, вопрос 20.5), непременно изолируйте объявление соответствующим typedef (см. вопрос 1.3). Если вам нужны числа, большие чем гарантируют встроенные типы, или вам нужны вычисления с произвольной точностью (или "multiple precision"); см. вопрос 18.15d. 1.2
Q: Почему не определены точные размеры стандартных типов?
A: Хотя С считается низкоуровневым языком в семействе языков высокого уровня, точный размер в битах относится к реализации, а не к стандарту. (Единственное место, где С позволяет определить размер и порядок бит - это битовые поля структур, см. вопросы 2.25 и 2.26). Большинству программ не нужен контроль за размером этих данных; многие программы, которые пытаются достигнуть полного контроля, лучше от этого не становятся.
Предполагается, что int
имеет размер машинного слова. Он подходит для большинства целочисленных переменных. Смотрите вопросы 1.1, 12.42 и 20.5.
1.3
Q: Так как С не определяет точные размеры типов, я могу определить, используя typedef
, int16
и int32
через short, int, long
в зависимости от машины. Это решит проблему контроля, верно?
A: Если вам действительно нужен контроль за размером типов, это правильный подход. Учтите, что:
- На некоторых машинах может не быть точного соответствия. (Например, на 36-битных машинах).
-
typedef
типов int16 или int32 бессмыслено, если оно будет означать "не менее" в определении размера, так какint
иlong
как правило уже означают "не менее 16 бит" и "не менее 32 бит" соответственно. -
typedef
не решит проблему порядка байт (например, при передаче данных или при попытке удовлетворить требованиям на расположение данных) - не надо определять свои типы данных через
typedef
, так как есть стандартный заголовочный файл<inttypes.h>
, содержащий полный набор нужных типов.
1.4
Q: Каким должен быть новый 64-битный тип на новых 64-битных машинах? A: Некоторые поставщики С компиляторов для 64-битных машин поддерживают тип long int длиной 64 бита. Другие же, опасаясь, что слишком многие уже написанные программы зависят отsizeof(int) == sizeof(long) == 32 бита
, вводят новый 64-битный тип long long (или __longlong).
Программисты, желающие писать мобильные программы, должны,
следовательно, изолировать 64-битные типы с помощью средства typedef.
Разработчики компиляторов, чувствующие необходимость ввести новый
целочисленный тип большего размера, должны объявить его как "имеющий
по крайней мере 64 бит" (это действительно новый тип, которого нет
в традиционном С), а не как "имеющий точно 64 бит".
См. также вопросы 1.3 и 18.15d.
1.5
Q: Что неправильно в декларации char* p1, p2;
При использовании p2 возникает ошибка A: Декларация правильная, за исключением того, что она не делает то, что вы от нее ждете. В декларации указателей * не является частью базового типа; это часть декларатора, содержащаего декларируемое имя (см. 1.21). То есть, в С синтаксис и интерпретация декларации не
тип идентификатор;
а скорее
базовый_тип то_что_дает_базовый_тип;
где "то_что_дает_базовый_тип" декларатор либо просто идентификатор, либо запись подобная
*p
или a[10]
или f()
, показывающая, что переменная определена как указатель на, массив из, или это функция, возвращающая базовый_тип.
(Конечно, могут быть более сложные деклараторы).
В декларации, описанной в вопросе, безотносительно того, на что намекает отсутствие пробела между базовым типом и , базовый тип char
и первый декларатор
p1, и так как декларатор содержит *, это определяет p1 как указатель-на-char. Декларатор для p2 не содержит ничего кроме p2
, то есть p2 определена как переменная типа char, вероятно не то, что вы хотели. Для декларации двух указателей в единой декларации используйте char *p1, *p2;
Так как * это часть декларатора, лучше использовать пробел, чтобы подчеркнуть это; написание
char*
вводит в заблуждение.
См. вопрос 1.13.
1.6
Q: Я пытаюсь определить указатель и захватить память, но это не работает. Что не так в этом коде?
char *p; *p = malloc(10);A: Декларированный указатель это
p
, а не *p
. См. вопрос 4.2.