Программирование >>  Перегруженные имена функций и идентификаторы 

1 ... 50 51 52 [ 53 ] 54 55 56 ... 210


Строка:

#line константа имя файла заставляет компилятор считать, например, в целях диагностики ошибок, что константа задает номер следующей строки исходного файла, и текущий входной файл именуется идентификатором. Если идентификатор отсутствует, то запомненное имя файла не изменяется.

Обзор типов

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

Классы

Классовые объекты могут присваиваться, передаваться функциям как параметры и возвращаться функциями. Другие возможные операции, как, например, проверка равенства, могут быть определены пользователем.

Функции

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

typedef int (*PF) (); extern g (PF); extern f ();

g (f);

Тогда определение g может иметь следующий вид:

g (PF funcp)

(*funcp) ();

Заметьте, что f должна быть описана явно в вызывающей программе, поскольку ее появление в g(f) не сопровождалось (.



Массивы, указатели и индексирование

Всякий раз, когда в выражении появляется идентификатор типа массива, он преобразуется в указатель на первый член массива. Из-за преобразований массивы не являются адресами. По определению операция индексирования [] интерпретируется таким образом, что E1[E2] идентично *((E1)+(E2)).

В силу правил преобразования, применяемых к +, если E1 массив и E2 целое, то E1[E2] относится к E2-ому члену E1.

Поэтому, несмотря на такое проявление асимметрии, индексирование является коммутативной операцией.

Это правило сообразным образом применяется в случае многомерного массива. Если E является n-мерным массивом ранга i*j*...*k, то возникающее в выражении E преобразуется в указатель на (n-1)-мерный массив ранга j*...*k.

Если к этому указателю, явно или неявно, как результат индексирования, применяется операция *, ее результатом является (n-1)-мерный массив, на который указывалось, который сам тут же преобразуется в указатель.

Например:

int x[3][5];

Здесь x - массив целых размером 3 на 5. Когда x возникает в выражении, он преобразуется в указатель на (первый из трех) массив из 5 целых. В выражении x[i], которое эквивалентно *(x+1), x сначала преобразуется, как описано, в указатель, затем 1 преобразуется к типу x, что включает в себя умножение 1 на длину объекта, на который указывает указатель, а именно объект из 5 целых.

Результаты складываются, и используется косвенная адресация для получения массива (из 5 целых), который в свою очередь преобразуется в указатель на первое из целых.

Если есть еще один индекс, снова используется тот же параметр; на этот раз результат является целым.

Именно из всего этого проистекает то, что массивы в Си хранятся по строкам (быстрее всего изменяется последний индекс), и что в описании первый индекс помогает определить объем памяти, поглощаемый массивом, но не играет никакой другой роли в вычислениях индекса.



Явные преобразования указателей

Определенные преобразования, включающие массивы, выполняются, но имеют зависящие от реализации аспекты. Все они задаются с помощью явной операции преобразования типов.

Указатель может быть преобразован к любому из целгх типов, достаточно больших для его хранения. То, какой из int и long требуется, является машинно-зависимым. Преобразующая функция также является машинно-зависимой, но предполагается, что она не содержит сюрпризов для того, кто знает структуру адресации в машине.

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

Указатель на один тип может быть преобразован в указатель на другой тип. Использование результирующего указателя может вызывать особые ситуации, если исходный указатель не указывает на объект, соответствующим образом выровненный в памяти.

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

Например, программа, выделяющая память, может получать размер (в байтах) размещаемого объекта и возвращать указатель на char; это можно использовать следующим образом.

extern void* alloc (); double* dp;

dp = (double*) alloc (sizeof double)); *dp= 22.0 / 7.0;

alloc должна обеспечивать (машинно-зависимым образом) то, что возвращаемое ею значение подходит для преобразования в указатель на double; в этом случае использование функции мобильно. Различные машины различаются по числу бит в указателях и требованиям к выравниванию объектов. Составные объекты выравниваются по самой строгой границе, требуемой каким-либо из его составляющих.



1 ... 50 51 52 [ 53 ] 54 55 56 ... 210

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика