Текст книги "Программирование на Objective-C 2.0"
Автор книги: Стивен Кочан
Жанр:
Программирование
сообщить о нарушении
Текущая страница: 29 (всего у книги 32 страниц)
Здесь объявляется переменная-структура типа date с именем tomorrow, и ей присваивается содержимое (ранее объявленной) переменной-структуры типа date с именем today.
ОбъявлениеКомпонента, которое имеет формат тип имяПоля: n
определяет доле длиной п бит внутри структуры, где п – целое значение. Поля могуг располагаться слева направо на одних машинах и справа налево на других. Если имяПоля опущено, то резервируется указанное число битов, но без ссылки. Если имяПоля опушено и п равно 0, то следующее поле выравнивается по границе следующего блока памяти, где размер блока зависит от реализации. Поле может иметь тип int, signed int или unsigned int. В зависимости от реализации поле типа int интерпретируется как signed или unsigned. К полю нельзя применять адресный оператор (&), и нельзя определять массивы молей. Объединения Общий формат union имя { ОбъявлениеКомпонента ОбъявлениеКомпонента } списокПеременных,
Здесь определяется объединение с заданным именем и компонентами, соот-ветствующими каждому объявлениюКомпонента. Каждый компонент объединения использует общую область памяти, и компилятор обеспечивает резервирова-ние области памяти, достаточной, чтобы вместить самый большой компонент данного объединения.
Переменные можно объявить непосредственно во время определения объединения, или их можно объявить в дальнейшем, используя форму записи union имя список именПеременнык,
при условии, что объединению было присвоено имя при его определении.
Программист сам должен следить за тем, чтобы значение, считываемое из объединения, соответствовало типу значения, которое было в последний раз сохранено в объединении. Первый компонент объединения можно инициали-зировать, заключив в фигурные скобки начальное значение, которое в случае глобальной union-переменной должно быть константным выражением. union shared { long long int I; long int w[2]; } swap = { Oxffffffff};
Для инициализации другого компонента нужно указать имя этого компо-нента, как в union shared swap2 = {.w[0] = 0x0, .w[1] = Oxffffffff };
Здесь объявляется union-переменная swap, и ее компоненту I присваивается шестнадцатеричное значение ffffffff.
Автоматическую union-переменную можно также инициализировать, при-своив ей объединение того же типа, например, union shared swap2 = swap; Указатели
Объявление переменной-указателя имеет базовый формат тип *имя,
Идентификатор имя объявляется с типом «указатель на тип»; типом может быть какой-либо базовый тип данных или производный тип данных. Например, int *ip;
объявляет ip как указатель на тип int, и struct entry *ер;
объявляет ер как указатель на структуру entry. Если определен класс Fraction, то Fraction "myFract;
объявляет myFract как объект типа Fraction, или, точнее, myFract используется для хранения указателя на структуру данных объекта после того, как создан экземпляр объекта и он присвоен этой переменной.
Указатели, которые указывают на элементы массива, объявляются для указания на тип элемента, содержащегося в этом массиве. Например, предыдущее объявление ip можно было бы также использовать для объявления указателя на массив целых элементов.
Допускаются также более сложные формы объявлений указателей. Напри-мер, char *tp[100];
объявляет tp как массив из 100 указателей на тип char, и struct entry (*fnPtr) (int);
объявляет fnPtr как указатель на функцию, которая возвращает структуру entry и принимает один аргумент типа int.
Можно проверить, является ли указатель пустым (null), сравнив его с кон-стантным выражением, значение которого равно 0. В реализации можно выб-рать внутреннее представление null-указателя в виде значения, отличного от 0. Однако сравнение между указателем с таким внутренним представлением и константным значением 0 должаю показывать равенство.
Преобразование указателей в целые значения и целых значений в указате-ли, а также размер целой переменной, необходимой для хранения указателя, зависят от типа машины.
Тип «указатель на void» – это обобщенный тип указателя. Язык Objective-C гарантирует, что указатель любого типа может быть присвоен void-указателю, и затем можно выполнить обратное присваивание без изменения его значения.
Тип id – это обобщенный указатель на объект. Любой объект любого класса может быть присвоен id-псременной, и наоборот.
За исключением этих двух особых случаев присваивание указателей различного типа не допускается, и обычно при такой попытке компилятор выдает предупреждающее сообщение. Перечислимые типы данных
Общий формат enum имя { епит_ /, епит_2,..} списокПеременнык,
Перечислимый тип с заданным именем определяется с перечисляемыми значениями enum l, епит_2,..., каждое из которых является идентификатором или идентификатором, после которого следует знак равенства и константное выра-жение. Можно также объявить спиажПеременных (с необязательными начальными значениями), и эти переменные будут иметь тип enum имя.
Компилятор присваивает перечисляемым идентификаторам последовательные целые значения, начиная с 0. Если идентификатор указан со знаком = и константным выражением, то идентификатору присваивается значение этого выражения. Последующим идентификаторам присваиваются значения, начиная со значения этого константного выражения плюс 1. Перечисляемые идентификаторы интерпретируются компилятором как константные целые значения.
Если нужно объявить переменную определенного ранее (и именованного) перечислимого тина, можно использовать конструкцию enum имя списокПеременных,
Если объявлена переменная определенного перечислимого типа, то ей мож-но присвоить значение только того же типа, хотя компилятор, возможно, не зарегистрирует это как ошибку. typedef
Оператор typedef используется, чтобы присвоить новое имя базовому или производному типу данных. Этот оператор не определяет какой-либо новый тип, а просто назначает новое имя для существующего типа. Поэтому переменные, объявленные с типом, имеющим новое имя, интерпретируются компилятором точно так же, как с типом, для которого дополнительно назначено это новое имя.
Создавая определение typedef, нужно действовать, как при объявлении обычной переменной. При этом нужно поместить новое имя типа там, где обычно ставится имя переменной. И, наконец, перед всем этим нужно поставить ключевое слово typedef.
В показанном ниже примере typedef struct { float х; float у; } POINT;
имя POINT связывается со структурой, содержащей два компонента типа float с именами х и у. Затем можно объявлять переменные типа POINT, например, POINT origin = {0.0, 0.0}; Модификаторы типа: const, volatile и restrict
Перед объявлением типа можно помещать ключевое слов const, чтобы сообщить компилятору, что это значение нельзя изменять. Например, const int х5= 100;
объявляет х5 как постоянную целую переменную – ей нельзя присвоить другое значение во время выполнения программы. Компилятор не обязательно будет реагировать на попытки изменения значения такой переменной.
Модификатор volatile явно указывает компилятору, что значение изменяется (обычно динамически). Если в выражении используется volatile-переменная, доступ к ее значению разрешается в любом месте, где она появляется.
Чтобы объявить переменную port17 как тип «volatile-указатель на char», можно написать следующую строку. char *volatile port 17;
С указателями можно использовать ключевое слово restrict. Это указание компилятору на возможность оптимизации (аналогично ключевому слову register для переменных). Ключевое слово restrict сообщает компилятору, что данный указатель будет единственной ссылкой на определенный объект, то есть не будет указываться никаким другим указателем в пределах той же области действия. Строки int * restrict intPtrA; int * restrict intPtrB;
сообщают компилятору, что в пределах области действия, где определены intPtrA и intPtrB, они никогда не будут указывать на одно и то же значение. Их использование для указания целых значений (например, в массиве) будет взаимоисключающим. Выражения
Имена переменных, имена функций, выражения в виде сообщений, имена массивов, константы, вызовы функций, ссылки на массивы, а также ссылки на структуры и объединения – все это интерпретируется как выражения. Применение унарного (одноместного) оператора к этим выражениям (в допустимых случаях) тоже является выражением, как и сочетание этих выражений с помощью бинарного (двумсстно1>) или тернарного (трехместного) оператора. И, наконец, выражение, заключенное в круглые скобки, тоже является выражением.
Отличное от void выражение любого типа, которое идентифицирует объект данных, называется lvalue (1-значением). Если ему может быть присвоено зна-чение, оно называется модифицируемым (изменяемым) lvalue.
Модифицируемые lvalue-выражения обязательны в определенных местах. Выражение в левой части оператора присваивания должно быть модифициру-емым lvalue. Унарный адресный оператор можно применить только к модифицируемом lvalue или к имени функции. И, наконец, операторы наращивания и уменьшения на 1 (инкремента и декремента) можно применять только к модифицируемым lvalue-выражениям. Сводка операторов Objective-C
В таблице В.4 приводится сводка различных операторов языка Objcctivc-C. Эти операторы приводятся в порядке убывания старшинства, и операторы, сгруп-пированные вместе, имеют одинаковый уровень старшинства.
Рассмотрим на следующем примере, как использовать таблицу В.4. b | с & d * е
Оператор умножения имеет более высокий приоритет, чем побитовые операторы OR (|) и AND (&), поскольку он находится выше обоих операторов в таблице В.4. Аналогичным образом, побитовый оператор AND имеет более высокий приоритет, чем побитовый оператор OR, поскольку первый находится в этой т аблице выше, чем второй. Поэтому данное выражение вычисляется в следующем порядке. b | ( с & ( d * е ))
Теперь рассмотрим следующее выражение, b % с * d
Табл. В.4. Сводка операторов Objective-C Оператор Описание Ассоциативность 0 Вызов функции Слева направо [] Ссылка на элемент массива или выражение с сообщением – || – -> Указатель ссылки на компонент структуры – || – . Ссылка на компонент структуры или вызов метода – || – – Унарный минус Справа налево + Унарный плюс – || – ++ Оператор инкремента – || – – Оператор декремента – || – ! Логическое отрицание – || – ~ Дополнение до нуля – || – * Ссылка на указатель (косвенным образом) – || – & Адрес – || – sizeof Размер объекта – || – (тип) Приведение типа (преобразование) – || – * Умножение Слева направо / Деление – || – % Взятие по модулю – || – + Сложение – || – – Вычитание – || – << Левый сдвиг – || – >> Правый сдвиг – || – < Меньше – || – <= Меньше или равно – || – > Больше – || – >= Больше или равно – || – == Равенство – || – != Неравенство – || – & Побитовый AND – || – ^ Побитовый XOR – || – | Побитовый OR – || – && Логический AND – || – || Логический OR – || – ?: Условный Справа налево = *= /= %= += -= & = ^= |= <<= >>= Операторы присваивания – || – , Оператор «запятая» – || -
Поскольку операторы взятия по модулю и умножения включены в одну группу таблицы В.4, они имеют одинаковый уровень старшинства. Эти операторы выполняются слева направо. Следующее выражение будет вычисляться как ( b % с ) * d
В следующем примере выражение ++а->b
будет вычисляться как ++(а->b)
поскольку оператор -> имеет более высокий приоритет, чем оператор ++.
И, наконец, поскольку операторы присваивания группируются справа на-лево, оператор а = b = 0;
будет вычисляться как а = (Ь = 0);
в результате чего переменным а и b будет присвоено значение 0. В случае выра-жения x[i] + ++i
не определено, в каком порядке компилятор будет выполнять оценку, – начиная с левой части оператора «плюс» или начиная с правой части. В данном случае порядок вычислений влияет на результат, поскольку значение i может быть увеличено до того, как будет вычисляться x[i],
В этом выражении порядок вычислений также не определен: x[i] = ++i
В этой ситуации не определено, когда значение i будет использовано как индекс для х, – до приращения i или после приращения.
Порядок вычисления аргументов функции или метода тоже не определен. Поэтому при вызове функции f(i, ++i);
или в выражении с сообщением [myFract setTo: i over: ++i];
возможно, что сначала будет выполнено приращение i, в результате чего функ-ции или методу будут переданы два одинаковых значения.
Язык Objectivc-C гарантирует, что операторы && и || будут вычисляться слева направо. Поэтому в случае && гарантируется, что второй операнд нс будет оцениваться, если первый равен 0; в случае || гарантируется, что второй операнд не будет оцениваться, если первый не равен 0. Этот факт необходимо учитывать при формировании таких выражений, как if ( dataFlag || [myData checkData])
поскольку в этом случае checkData вызывается, только если значение dataFlag равно 0. Еще один пример. Если в определении объект-массив а содержит п элементов, то оператор, который начинается с if (index >= 0 && index < n && ([a objectAtlndex: index] == 0))
является ссылкой на элемент этого массива, только если index является допустимым индексом в этом массиве. Константные выражения
Константное выражение – это выражение, каждый из членов которого является константным значением. Константные выражения необходимы в следующих ситуациях.
Как значение после case в операторе switch.
Для указания размера массива.
Чтобы присвоить значение идентификатору перечисления.
Чтобы указать размер битового поля в определении структуры.
Чтобы присвоить начальные значения внешним или статическим переменным.
Чтобы задать начальные значения для глобальных переменных.
Как выражение после #if в препроцессорном операторе #if. В первых четырех случаях константное выражение должно состоять из це-лых констант, символьных констант, перечисляемых констант и выражений sizeof. Могут использоваться только арифметические операторы, побитовые операторы, операторы отношения, оператор с условным выражением и опера-тор приведения тина (cast).
В пятом и шестом случаях помимо вышеперечисленных правил может ис-пользоваться явно или неявно адресный оператор. Однако он может приме-няться только к внешним или статическим переменным или функциям. На-пример, выражение &х+ 10
будет допустимым константным выражением, если х является внешней или статической переменной. Кроме того, выражение &а[10] – 5
янляется допустимым константным выражением, если а является внешним или статическим массивом. И, наконец, поскольку &а[0] эквивалентно выражению а + sizeof (char) * 100
оно тоже является допустимым константным выражением.
В последней ситуации, где необходимо константное выражение (после #if), применяются такие же правила, как для первых четырех случаев, за исключе-нием того, что не могут использоваться оператор sizeof, константы перечисления и оператор приведения типа (cast). Однако разрешается специальный определенный оператор (см. раздел «Директива if»). Арифметические операторы
При условии, что а, b выражения любого базового типа данных за исключением void; i, j выражения любого целого типа данных
выражение -а изменяет знак а на противоположный; +а дает значение а; а + b выполняет сложение а и b; а – b выполняет вычитание b из а; а * b выполняет умножение а на b; а / b выполняет деление а на b; i % j дает остаток от деления i на j.
В каждом выражении выполняются обычные арифметические преобразо-вания над операндами (см. ниже раздел «Преобразование базовых типов дан-ных»), Если а – переменная без знака (unsigned), то для вычисления -а сначала выполняется целочисленное расширение, выполняется вычитание из большего значения расширенного типа и к результату добавляется 1.
При делении двух целых значений выполняется усечение результата. Если один из операндов меньше нуля, то направление усечения не определено (то есть -3/2 может дать на некоторых машинах -1 и -2 на других); в противном случае усечение всегда выполняется в сторону 0(3/2 всегда дает 1). Сводку арифметических операций с указателями см. в разделе «Базовые операции с указателями». Логические операторы
При условии, что а, b выражения любого базового типа данных за исключением void или оба операнда являются указателями;
выражение а && b имеет значение 1, если а и Ь не равны нулю, и значение 0 в противном случае (Ь оценивается только в том случае, если а отлично от нуля); а || b имеет значение 1, если а или b не равно нулю, и значение 0 в противном случае (Ь оценивается только в том случае, если а отлично от нуля); ! а имеет значение 1, если а равно 0, и значение 0 в противном случае.
К а и b применяются обычные арифметические преобразования (см. ниже раздел «Преобразование базовых типов данных»). Во всех случаях результат имеет тип int. Операторы отношения
При условии, что а, Ь выражения любого базового типа данных за исключением void или оба операнда являются указателями;
выражение а < b имеет значение 1, если а меньше Ь, и значение 0 в противном случае; а <= b имеет значение 1, если а меньше или равно Ь, и значение 0 в противном случае; а > Ь имеет значение 1, если а больше Ь, и значение 0 в противном случае; а >= b имеет значение 1, если а больше или равно Ь, и значение 0 в противном случае; а != b имеет значение 1, если а не равно Ь, и значение 0 в противном случае.
К а и b применяются обычные арифметические преобразования (см. ниже раздел «Преобразование базовых типов данных»). Первые четыре оператора отношения имеют смысл для указателей, только если они указывают на один и тот же массив либо на компоненты одной структуры или объединения. Во всех случаях результат имеет тип int. Побитовые операторы
При условии, что i, j, п выражения любого целого типа данных;
выражение i & j выполняет побитовую операци ю AN D с i и j; i | j выполняет побитовую операцию OR с i и j; i А j выполняет побитовую операцию XOR с i и j; ~i получает дополнение до нуля для i; i << n выполняет сдвиг i влево на n бит; i >> n выполняет сдвиг i вправо на n бит.
К этим операндам применяются обычные арифметические преобразования за исключением « и », когда для каждого операнда выполняется целочисленное расширение (см. ниже раздел «Преобразование базовых типов данных»). Если количество битов смешения меньше нуля либо больше или равно числа битов в объекте смешения, то результат смешения не определен. На некоторых машинах правое смещение является арифметическим (заполняется бит знака), а на других – логическим (заполнение нулем). Тип результата операции смещения такой же, как у расширяемого левого операнда. Операторы наращивания и уменьшения на 1 (операторы инкремента и декремента)
При условии, что I модифицируемое lvalue-выражение, тип которого не уточнен как const;
выражение ++I увеличивает I на 1, после чего I используется как значение выражения; I++ использует I как значение выражения и затем увеличивает I на 1; –I уменьшает I на I, после чего I используется как значение выражения; I– использует I как значение выражения и затем уменьшает 1 на I.
Ниже в разделе «Базовые операции с указателями» описываются эти операции с указателями. Операторы присваивания
При условии, что I модифицируемое lvalue-выражение, тип которого не уточнен как const; op любой оператор, который можно использовать как оператор присваивания (см. таблицу В.4); а выражение;
выражение I = а сохраняет значение а в I; I ор= а применяет орк I и а, сохраняя результат в I.
Если в первом выражении а имеет один из базовых типов данных (за исклю-чением void), то а преобразуется для соответствия типу I. Если I – указатель, то а должен быть указателем того же типа, void-указателем или null-указателем.
Если I – void-указатель, то а может быть указателем любого типа. Второе выражение интерпретируется как I = I ор (а), за исключением того, что I оценивается только один раз (например, в случае x[i++] += 10). Условный оператор
При условии, что а, Ь, с выражения;
выражение а ? b: с получает значение Ь, если а отлично or нуля, или с в противном случае. Вычисляется только выражение b или с.
Выражения Ь и с должны иметь одинаковый тип данных. Если это не так, но оба выражения имеют арифметические типы данных, то применяются обычные арифметические преобразования, чтобы сделать их типы одинаковыми. Если одно из них является указателем, а другое равно 0, то второе выражение используется как null-указатель того же типа, что и первое. Если одно из них является указателем на void, а другое является указагелем на другой тип, то вто-рое преобразуется в указатель на void и результат имеет такой же тип. Оператор приведения типа
При условии, что тип имя какого-либо базового типа данных, перечислимый тип данных (с ключевым словом enum) или тип, определенный как typedef либо приведенный тип данных; а выражение;
выражение ( тип) преобразует а в указанный тип.
Отметим, что использование типа в круглых скобках при объявлении или определении метода не является примером использования оператора приведе-ния типа. Оператор sizeof
При условии, что тип совпадает с описанием в предыдущем разделе; а выражение;
выражение sizeof (тип) имеет значение, равное числу байтов памяти, необходимых для зна-чения указанного типа; sizeof а имеет значение, равное числу байтов памяти, необходимых для ре-зультата вычисления а.
Для типа char результат по определению равен 1. Если а – имя массива, для которого задан размер (явным образом или неявно через инициализацию), и это не формальный параметр и не extern-массив, для которого не указан размер, то sizeof а дает число байтов, необходимых для хранения этих элементов в а.
Если а – имя класса, то sizeof (а) дает размер структуры, необходимой для хранения экземпляра а.
Целое значение, которое дает оператор sizeof, имеет тип size_t, который определен в стандартном header-файле .
Если а – массив переменной длины, то данное выражение вычисляется на этапе выполнения; в противном случае оно вычисляется на этапе компиляции и его можно использовать в константных выражениях (см. выше раздел «Кон-стантные выражения»). Оператор «запятая»
При условии, что а, b выражения;
выражение а, Ь означает вычисление а и затем вычисление Ь. Результирующее выражение имеет тип и значение b. Базовые операции с массивами
При условии, что а объявляется как массив из п элементов; i выражение любого целого типа данных; v выражение;
выражение а[0] является ссылкой на первый элемент а; а[n -1] является ссылкой на последний элемента; a[i] является ссылкой на элемент а с номером i; a[i] = v сохраняет значение v в ар].
В каждом случае тип результата совпадает с типом элементов, содержащихся в а. Сводку операций с указателями и массивами см. ниже в разделе «Базовые операции с указателями». Базовые операции со структурами
Примечание. Эго также относится к объединениям (union).
При условии, что х модифицируемое lvalue-выражение типа struct s; у выражение типа struct s; m имя одно из компонентов структуры S; obj любой объект; М любой метод; v выражение;
выражение х является ссылкой на всю структуру и имеет тип struct s; y.m является ссылкой на компонент m структуры у и имеет тип, объявленный для компонента т; x.m = v присваивает v компоненту m выражения х и имеет тип, объявленный для компонента т; х = у присваивает х значение у и имеет тип struct s; f (у) вызывает функцию f, передавая как аргумент содержимое структуры у (внутри f должен быть объявлен формальный параметр типа struct s); [obj М: у] вызывает метод М для объекта obj, передавая как аргумент содержимое структуры у (внутри метода этот параметр должен быть объявлен как тип struct s); return у; возвращает структуру у (возвращаемое значение, объявленное для функции или метода, должно иметь тип struct s). Базовые операции с указателями
При условии, что х lvalue-выражение типа t, pt модифицируемое lvalue-выражение типа «указатель на t»; v выражение;
выражение &х дает указатель на х и имеет тип «указатель на t»; pt = &х задает pt как указатель на х и имеет тип «указатель на Ь>; pt = 0 присваивает pt null-указатель; pt == 0 проверяет, является ли pt null-указателем; *pt является ссылкой на значение, указываемое pt и имеет тип t *pt = v сохраняет значение v в том месте, на которое указывает pt, и имеет тип t Указатели на массивы
При условии, что а массив элементов типа t; ра1 модифицируемое lvalue-выражение типа «указатель на t», которое указывает на какой-либо элемент в а; ра2 lvalue-выражение типа «указатель на Ь>, которое указывает на какой-либо элемент в а или на элемент, следующий за последним элементов в а; v выражение; п целое выражение;
выражение a, &a, &a[0] каждое дает указатель на первый элемент; &a[n] создает указатель на элемент с номером n массива а и имеет тип «указатель на t»; *pa1 является ссылкой на элемент, на который указывает pal, и имеет тип «t»; *pa1 = v сохраняет значение v в элементе, на который указывает pal, и имеет тип «t»; ++pa1 задает указатель ра1 на следующий элемент а независимо от типа элементов, содержащихся в а, и имеет тип «указатель на /»; –pa1 задает указатель pal на предыдущий элемента независимо от типа элементов, содержащихся в а, и имеет тип «указатель на i»; *++pa1 увеличивает pal на 1 и затем ссылается назначение в а, на которое указывает pal; имеет тип t, *pa1++ ссылается на значение в а, на которое указывает ра1, прежде чем увеличить ра1 на 1; имеет тип к pa1 + n создает указатель, который указывает в а на n элементов дальше, чем ра1, и имеет тип «указатель на /»; pa1 – n создает указатель, который указывает в а на n элементов ближе, чем ра1, и имеет тип «указатель на /»; *(pa1 + n) = v сохраняет значение v в элементе, на который указывает ра1 + n, и имеет тип « указатель на f»; pa1 < pa2 проверяет, что ра1 указывает в а более ближний элемент, чем ра2; имеет тип int (для сравнения двух указателей можно использовать любые операторы отношения); pa2 – pa1 дает число элементов, содержащихся в а между указателями ра2 и pal (в предположении, что ра2 указывает на элемент, который находится дальше, чем ра1), и имеет значение целого типа; a + n создает указатель на элемент массива а с номером п и имеет тип «указатель на t»; эквивалентно во всех отношениях выражению &а[n]; *(а + n) ссылка на элемент массива а с номером п, имеет тип «fa и эквивалентно во всех отношениях выражению а[п].
Целое значение, получаемое в результате вычитания двух указателей, имеет конкретный тип ptrdiffj, который определен в стандартном header-файле
При условии, что х модифицируемое lvalue-выражение типа struct s; ps модифицируемое lvalue-выражение типа «указатель на struct ss>; m имя какого-либо компонента структуры s, имеющего тип t; v выражение;
выражение &х дает указатель на х и имеет тип «указатель на struct s»; ре – &х задает ре как указатель па х, имеющий тип «указатель на struct s>>; ps->m является ссылкой на компонент m структуры, указанной с помощью ps, и имеет тип t, (*ps).m тоже является ссылкой на этот компонент и эквивалентно во всех отношениях выражению ps->m; ps->m = v сохраняет значение v в компоненте m структуры, указанной с помо-щью ps, и имеет тип t. Составные литералы
Составной литерал (compound literal) представляет собой имя типа, заключен-ное в круглые скобки, после которого следует список инициализации. В ре-зультате создается неименованное значение указанного типа, область действия которого ограничена блоком, в котором оно создано, или глобальной областью действия, если оно определено вне блока. В последнем случае все инициализаторы должны включать только константные выражения.
Например, (struct point) {.х = 0, .у = 0)
является выражением, которое создает структуру типа struct point с указанными начальными значениями. Его можно присвоить другой структуре типа struct point, например, origin = (struct point) {.x = 0, .у = 0);
Или его можно передать функции или методу, если предполагается, что ар-гумент имеет тип struct point, например, moveToPoint ((struct point) {.x = 0, .у = 0});
Можно также определять типы, отличные от структур. Например, если intPtr имеет тип int *, то оператор intPtr = (int [100]) {[0] = 1, [50] = 50, [99] = 99 };
(который может находиться в любом месте программы) задает intptr, указывающий на массив, содержащий 100 целых элементов, причем первые 3 элемента инициализируются указанным образом.
Если размер массива не задан, он определяется списком инициализации. Преобразование базовых типов данных
Язык Objective-C преобразует операнды арифметических выражений в заранее определенном порядке, который называется обычными арифметическими преобразованиями .
Если один из операндов имеет тип long double, второй операнд преобразуется в long double, таким же будет тип результата.
Если один из операндов имеет тип double, второй операнд преобразуется в double, таким же будет тип результата.
Если один из операндов имеет тип float, второй операнд преобразуется в тип float, таким же будет тип результата.
Если один из операндов имеет тип _Bool, char, short int, является битовым полем типа int или является перечислимым типом данных, то он преобразуется в тип int, если int может полностью представлять его диапазон значений; в противном случае он преобразуется в unsigned int. Если оба операнда имеют одинаковый тип, таким же будет тип результата.
Если оба операнда указаны как signed или оба как unsigned, то целый тип меньшего размера преобразуется в больший целый тип, и таким же будет тип результата.
Если операнд с атрибутом unsigned имеет размер, который не меньше размера операнда с атрибутом signed, то операнд signed преобразуется в тип операнда unsigned, таким же будет тип результата.
Если операнд с атрибутом signed может представлять все значения операнда unsigned, то второй преобразуется в тип первого, если он может полностью представлять весь диапазон его значений, таким же будет тип результата.
Есл и был достигнут этот шаг, то оба операнда преобразуются в тип с атрибутом unsigned, соответствующий типу с атрибутом signed.
Шаг 4 называется более формально целочисленным расширением. Преобразование операндов нормально проходит в большинстве ситуаций, хотя следует отметить следующие особенности.
Преобразование char в int может вызвать на некоторых машинах расширение на знаковый бит, если char не объявлен как unsigned.
Преобразование целого типа с атрибутом signed в целый тип большего раз-мера вызывает расширение влево за счет знакового бита; преобразование целого типа с атрибутом unsigned в целый тип большего размера вызывает заполнение левою бита нулем.