355 500 произведений, 25 200 авторов.

Электронная библиотека книг » Стивен Кочан » Программирование на Objective-C 2.0 » Текст книги (страница 4)
Программирование на Objective-C 2.0
  • Текст добавлен: 19 сентября 2016, 13:02

Текст книги "Программирование на Objective-C 2.0"


Автор книги: Стивен Кочан



сообщить о нарушении

Текущая страница: 4 (всего у книги 32 страниц)

Тип данных id часто используется в этой книге. Тип id является основой таких важных средств в Objective-C, как полиморфизм {polymorphism) и динамическое связывание (dynamic binding). (Подробнее см. главу 9.)

В таблице 4.1 приводится сводка базовых типов и квалификаторов.

Табл. 4.1. Базовые типы данных Тип Примеры констант Символы формата NSLog char 'a', 'n' %c short int – %hi, %hx, %ho unsigned short int – %hu, %hx, %ho int 12, -97, OxFFEO, 0177 %i, %x, %o unsigned int 12u, 100U, OXFFu %u, %x, %o long int 12L, -2001, OxffffL %li, %lx, %lo unsigned long int 12UL, 100ul, OxffeeUL %lu, %lx, %lo long long int 0xe5e5e5e5LL, 500ll %lli, %llx, &llo unsigned long long int 12ull, OxffeeULL %llu, %llx, %llo float 12.34f, 3.1e-5f, 0x1.5p10, 0x1 P-1 %f, %e, %g, %a double 12.34, 3.1 e-5, 0x.1p3 %f, %e, %g, %a long double 12.341, 3.1 e-5l %Lf, $Le, %Lg id nil %p 4.2. Арифметические выражения

В Objective-C, как практически во всех языках программирования, знак «плюс» (+) используется для сложения двух значений, знак «минус» – для вычитания двух значений, звездочка (*) – для умножения двух значений, а слэш (/) – для деления двух значений. Эти операторы называются бинарными (binary) арифметическими операторами, поскольку они работают с двумя значениями, или членами. Старшинство операторов

Вы уже видели, как в Objective-C выполняется простая операция, например, сложение. В следующей программе показаны операции вычитания, умножения и деления. В последних двух операторах этой программы показано, что оператор может иметь более высокий приоритет, или старшинство (precedence) по сравнению с другим оператором. Любой оператор в Objective-C имеет свой приоритет.

Приоритет определяет порядок вычисления выражения, содержащего более одного оператора: оператор с более высоким приоритетом вычисляется первым. Выражения, содержащие операторы с одинаковым приоритетом, вычисляются слева направо или справа налево (в зависимости от оператора). Это свойство ассоциативности (associative) оператора. В приложении В приводится полный список старшинства операторов и правил ассоциативности. // Использование арифметических операторов #import int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int a = 100; int b = 2; int c = 25; int d = 4; int result; result = a – b; //вычитание NSLog (@"a – b = %i", result); result = b * с; //умножение NSLog (@"b * c = %i", result); result = a / с; //деление NSLog (@"a / c = %i", result); result = а + b * с; //старшинство NSLog (@"а + b * с = %i", result); NSLog (@"а * b + с * d = %i", а * b + с * d); [pool drain]; return 0; }

Вывод программы 4.2 a – b = 98 b * c = 50 a/c = 4 a + b * c = 150 a * b + c * d = 300

После объявления целых переменных a, b, с, d и result программа присваивает результат вычитания b из а переменной result и затем выводит ее значение с по-мощью вызова NSLog.

В следующей строке значение b умножается на значение с, и произведение сохраняется в переменной result: result = b * с;

Результат умножения выводится с помощью вызова NSLog. В следующей строке программы используется оператор деления и с помощью NSLog выводится результат деления а на с, то есть 100 на 25.

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

Результат следующего выражения не равен 2550 (102 х 25); вместо этого NSLog выводит значение 150. а + b * с

Objective-C, как и большинство других языков программирования, выполняет несколькох операций над членами выражения по определенному порядку. Вычисление выражения обычно происходит слева направо, но операции умно-жения и деления имеют приоритет над операциями сложения и вычитания. Поэтому система вычисляет выражение а + b * с

следующим образом: а + (b * с)

Для изменения порядка вычисления членов внутри выражения можно ис-пользовать круглые скобки. Показанное выше выражение является допустимым выражением Objective-C. Следующую строку можно подставить в программу 4.2, чтобы получить те же результаты: result = а + (b * с);

Но переменной result будет присвоено значение 2550, если использовать следующее выражение: result = (а + b) * с;

Значение а (100) будет сложено со значением b (2) до умножения на с (25). Круглые скобки можно вкладывать друг в друга; выражение будет вычисляться, начиная с внутренних круглых скобок. Убедитесь, что число закрывающих скобок равно числу открывающих. В последней выполняемой строке программы 4.2 выражение передается как аргумент процедуре NSLog без присваивания этого выражения какой-либо переменной. Выражение а * b + с * d

вычисляется по описанным выше правилам как (а Ь) + (с d) то есть (100 * 2)+ (25 *4)

Результат 300 передается процедуре NSLog. Целочисленная арифметика и унарный оператор «минус»

В программе 4.3 демонстрируется то, что мы только что обсуждали, и вводится понятие целочисленной арифметики. // Другие арифметические выражения #import int main (int argc, char *argv[]) { NSAutoreleasePooI * pool = [[NSAutoreleasePool alloc] init]; int a = 25; int b = 2; int result; float c = 25.0; float d = 2.0; NSLog (@"6 + a / 5 * b = %i", 6 + a / 5 * b); NSLog (@"a / b * b = %i", a / b * b); NSLog (@"c/d*d = %f", c/d*d); NSLog (@"-a = %i" -a); [pool drain]; return 0; }

Вывод программы 4.3 6 + a/5*b=16 a / b * b = 24 c / d * d = 25.000000 -a = -25

Мы вставили дополнительные пробелы между int и объявлением переменных а, b и result в первых трех выполняемых строках, чтобы выровнять объявление каждой переменной. Это делает программу более удобной для чтения. Вы могли заметить, что каждый арифметический оператор окружен пробелами. Обычно вы можете добавлять дополнительные пробелы там, где разрешен один пробел. Это не обязательно, но упрощает чтение программы.

Вычисление выражения в первом вызове NSLog программы 4.3 происходит следующим образом.

Поскольку деление имеет более высокий приоритет, чем сложение, сначала значение а (25) делится на 5. Это дает промежуточный результат 5.

Поскольку умножение имеет более высокий приоритет, чем сложение, про-межуточный результат 5 умножается на 2 (значение Ь), что дает новый про-межуточный результат 10.

Наконец, выполняется сложение б и 10, что дает конечный результат 16.

Во второй строке, казалось бы, деление на b и последующее умножение на b должно дать значение переменной а, то есть присвоенной ей значение 25. Но результаты вывода дают значение 24. Дело в том, что выражение было вычислено с помощью целочисленной арифметики.

Переменные а и b были объявлены с типом int. Если вычисляемый член в выражении содержит два целых значения, Objective-C выполняет операцию, используя целочисленную арифметику, при которой дробная часть отбрасыва-ется. Поэтому при делении значения а на значение b (25 делится на 2) мы полу-чаем промежуточный результат 12, а не 12.5, как можно было бы ожидать. Ум-ножение этого промежуточного результата на 2 дает конечный результат 24.

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

Решение о выборе между типом переменной float или int нужно принимать, исходя из предполагаемого использования переменной. Если вам не нужная дробная часть, используйте целую переменную. Результирующая программа будет работать быстрее на многих компьютерах. С другой стороны, если вам нужна точность со знаками после десятичной точки, то выбор очевиден. Остается только решить, какой тип использовать: float или double. Ответ на этот вопрос зависит от точности чисел, с которыми вы работаете, и от их величины.

В последнем операторе NSLog значение переменной берется со знаком «ми-нус» с помощью унарного (одноместного) оператора. Унарный (unary) оператор применяется к одному значению – в отличие от бинарного оператора, который применяется к двум значениям. Знак «минус» как бинарный оператор приме-няется для вычитания одного значения из другого, а как унарный оператор – для изменения знака значения.

Унарные операторы «минус» и «плюс» имеют более высокий приоритет, чем все остальные арифметические операторы. Таким образом, следующее выра-жение дает результат умножения -а на Ь: с = -а * Ь;

В таблице из приложения В приводится сводка операторов с их приоритета-ми. Оператор остатка от деления

Последний арифметический оператор, представленный в этой главе – это опе-ратор остатка от деления, который указывается знаком процента (%). Чтобы определить, как работает этот оператор, рассмотрим программу 4.4. // Оператор остатка от деления #import int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; int a = 25, b = 5, c = 10, d = 7; NSLog (@"а %% b = %i", а % b); NSLog (@"а %% с = %i", а % с); NSLog (@"а %% d = %i", а % d); NSLog (@"а / d * d + а %% d = %i", a / d * d + a % d); [pool drain]; return 0; }

Вывод программы 4.4 a % b = 0 a % c = 5 a % d = 4 a / d * d + a % d = 25

В процедуре main переменные a, b, с и d определяются в одной строке.

Символ после знака «%» указывает, как должен выводиться следующий ар-гумент. Если следующим символом является еще один знак процента, процедура NSLog выводит этот знак и вставляет его в соответствующую позицию вывода программы.

Из результатов вывода можно заключить, что оператор % вычисляет остаток отделения первого значения на второе. В первом примере остаток отделения 25 на 5 равен 0. Если разделить 25 на 10, то мы получим в остатке 5, что подтверждается второй строкой вывода. Деление 25 на 7 дает в остатке 4, что показано в третьей строке вывода.

Теперь рассмотрим арифметическое выражение, вычисляемое в последней строке. Операции между двумя целыми значениями выполняются с помощью целочисленной арифметики, поэтому остаток отделения двух целых значений просто отбрасывается. Деление 25 на 7 (выражение а / d) дает промежуточный результат 3. Умножение этого значения на значение d (оно равно 7) дает проме-жуточный результат 21. И, наконец, остаток от деления а на d (в выражении а % d) дает конечный результат 25 (21 + 4). Результат равен значению переменной а, и это не является случайным совпадением. Следующее выражение всегда равно значению а, если а и b являются целыми значениями. a/b*b + a%b

На самом деле оператор остатка от деления (%) предназначен для работы только с целыми значениями.

Что касается приоритета операций, то оператор остатка от деления имеет одинаковый приоритет с операторами умножения и деления. Отсюда следует, что выражение table + value % TABLE_SIZE будет вычисляться как table + (value % TABLE_SIZE) Преобразования между целыми значениями и значениями с плавающей точкой

Чтобы эффективно разрабатывать программы на Objective-C, необходимо знать правила, применяемые в Objective-C для неявного преобразования между целыми значениями и значениями с плавающей точкой. В программе 4.5 показаны примеры некоторых простых преобразований между числовыми типами данных. // Основные преобразования в Objective-C #import int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; float f1 = 123.125, f2; int M, i2 = -150; i1 = f1; // преобразование типа float в целый тип int NSLog (@"%f assigned to an int produces %i", f1, i1); f1 = i2; // преобразование целого типа в тип float NSLog (@"%i assigned to a float produces %f, i2, f1); f1 = i2 / 100; // деление целого значения на целое NSLog (@"%i divided by 100 produces %f", i2, f 1); f2 = i2 / 100.0; // деление целого значения на тип float NSLog (@"%i divided by 100.0 produces %f", i2, f2); f2 = (float) i2 / 100; // оператор приведения типа NSLog (@"(float) % divided by 100 produces %f", i2, f2); [pool drain]; return 0; }

Вывод программы 4.5 123.125000 assigned to an int produces 123 -150 assigned to a float produces -150.000000 -150 divided by 100 produces -1.000000 -150 divided by 100.0 produces -1.500000 (float) -150 divided by 100 produces -1.500000

Если значение с плавающей точкой присваивается переменной целого типа, дробная часть этого числа отбрасывается. Тем самым, если в приведенной про-грамме значение f1 присваивается И, то дробная часть числа 123.125 отбрасывается, то есть в И сохраняется его целая часть (123). Это показано в первой строке вывода программы.

Если значение целой переменной присваивается переменной с плавающей точкой, это не вызывает какого-либо изменения в значении числа; система просто преобразует это значение и сохраняет его в переменной с плавающей точкой. Во второй строке вывода программы показано, что значение 2 (-150) правильно преобразовано и сохранено в переменной f1 типа float.

В следующих двух строках вывода программы показаны две ситуации, о ко-торых нужно помнить при формировании арифметических выражений. В первом случае действует целочисленная арифметика, о которой мы говорили в пре-дыдущем разделе. Если два операнда выражения являются целыми (это относится и к целым переменным с модераторами short, unsigned и long), то операция выполняется по правилам целочисленной арифметики. Поэтому любая дробная часть, полученная в операции деления, отбрасывается, даже если результат присваивается переменной с плавающей точкой (как в этой программе). Если целая переменная i2 делится на целую константу 100, то система выполняет целочисленное деление. Поэтому результат деления -150 на 100, равный -1, сохраняется в переменной типа float f1.

Следующее деление применяется к целой переменной и константе с плава-ющей точкой. Любая операция, выполняемая с двумя значениями в Objective– С, выполняется как операция с плавающей точкой, если хотя бы одно из значений является переменной или константой с плавающей точкой. Поэтому при делении значения i2 на 100.0 система выполняет деление с плавающей точкой и дает результат -1.5, который присваивается переменной типа f1 float. Оператор приведения типа

При объявлении и определении методов для объявления типов возвращаемого значения и аргументов тип включается в круглые скобки. Внутри выражений этот способ применяется для другой цели.

В последней операции деления программы 4.5 появляется оператор приве-дения типа: f2 = (float) i2 / 100; // оператор приведения типа

В данном случае для вычисления выражения оператор приведения типа ис-пользуется для преобразования значения переменной i2 в тип float. Это оператор не влияет на значение переменной i2; это унарный оператор. Выражение (float) а не влияет на значение а – аналогично выражению -а.

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

В этом примере выражение (int) 29.55 + (int) 21.99

вычисляется в Objective-C как 29 + 21

поскольку приведение значения с плавающей точкой к целому типу приводит к отбрасыванию дробной части. Выражение (float) 6 / (float) 4

дает значение 1.5, как и в следующем выражении: (float) 6/4

Оператор приведения типа часто используется для принудительного приве-дения объекта, имеющего обобщенный тип id, к объекту определенного класса. Например, в следующих строках выполняется преобразование значения пере-менной myNumber типа id к объекту класса Fraction: id myNumber; Fraction *myFraction; myFraction = (Fraction *) myNumber;

Результат этого преобразования присваивается переменной myFraction типа Fraction. 4.3. Операторы присваивания

Язык Objective-C позволяет объединять арифметические операторы с оператором присваивания в обобщенном формате ор=

В этом формате ор – любой из арифметических операторов, включая +, *, / или %. Кроме того, ор может быть любым из битовых операторов для смещения и маскирования, которые описываются ниже.

Рассмотрим строку count += 10;

Оператор «плюс равно» += добавляет выражение, находящееся справа от этого оператора, к переменной, находящейся слева от оператора, и сохраняет результат в этой переменной. Таким образом, приведенная выше строка экви-валентна следующей строке: count = count + 10;

В следующем выражении используется оператор «минус равно» для вычи-тания 5 из значения переменной counter: counter -= 5

Это эквивалентно выражению counter = counter – 5

А теперь чуть более сложное выражение: а /= b + с

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

Это выражение эквивалентно следующему: а = а / (b + с)

Операторы присваивания используются потрем причинам. Во-первых, про-грамму проще писать: то, что находится слева от оператора присваивания, не нужно повторять с правой стороны. Во-вторых, результирующее выражение проще читать. В третьих, программы могут выполняться быстрее, поскольку компилятор иногда генерирует более короткий код для вычисления выражения. 4.4. Класс Calculator

Теперь можно определить новый класс. Мы создадим класс Calculator для сложения, умножения, вычитания и деления чисел. Как и обычный калькулятор, он должен следить за промежуточной суммой, которую называют накапливающим сумматором, или просто сумматором (accumulator). Поэтому соответствующие методы должны позволять вам задавать для сумматора определенное значение, выполнять его сброс (задавать равным нулю) и считывать значение, когда закончатся вычисления. В программе 4.6 содержится определение этого класса и тестовая программа. // Реализация класса Calculator #import @interface Calculator: NSObject { double accumulator; } // методы для сумматора (accumulator) -(void) setAccumulator: (double) value; -(void) clear; -(double) accumulator; // арифметические методы -(void) add: (double) value; -(void) subtract: (double) value; -(void) multiply: (double) value; -(void) divide: (double) value; @end @implementation Calculator -(void) setAccumulator: (double) value { accumulator = value; ) -(void) clear { accumulator = 0; } -(double) accumulator { return accumulator; } -(void) add: (double) value { accumulator += value; } -(void) subtract: (double) value { accumulator -= value; } -(void) multiply: (double) value { accumulator *= value; } -(void) divide: (double) value { accumulator /= value; } @end int main (int argc, cfiar *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; Calculator *deskCalc; deskCalc = [[Calculator alloc] init]; [deskCalc clear]; [deskCalc setAccumulator: 100.0]; [deskCalc add: 200.]; [deskCalc divide: 15.0]; [deskCalc subtract: 10.0]; [deskCalc multiply: 5]; NSLog (@"The result is %g", [deskCalc accumulator]); [deskCalc release]; [pool drain]; return 0; }

Вывод программы 4.6 The result is 50

Класс Calculator имеет только одну переменную экземпляра типа double, со-держащую значение сумматора. Сами определения методов достаточно просты. Обратите внимание на сообщение, которое вызывает метод multiply: [deskCalc multiply: 5];

Этому методу передается целый аргумент, хотя в методе предполагается значение типа double. Здесь нет никакой проблемы, поскольку числовые аргументы, передаваемые методам, автоматически преобразуются в соответствующий предполагаемый тип. Метод multiply: предполагает значение типа double, поэтом при вызове функции целое значение 5 автоматически преобразуется в значение с плавающей точкой двойной точности. Здесь преобразование происходит автоматически, по практика программирования все же рекомендует задавать соответствующие типы аргументов при вызове методов.

В отличие от класса Fraction, где можно работать со многими дробями, в пашей программе, возможно, потребуется работа только с одним объектом Calculator. Имеет смысл определить новый класс, чтобы упростить работу с этим объектом. В какой-то момент вам захочется добавить графический интерфейс к своему калькулятору, чтобы пользователь мог реально щелкать кнопками на экране, как в широко распространенном приложении calculator. 4.5. Битовые операторы

Некоторые операторы в языке Objective-C работают с определенными битами внутри числа. Эти операторы представлены в таблице 4.2.

Табл. 4.2. Битовые операторы Символ Операция & Побитовое И | Побитовое включающее ИЛИ ^ Побитовое исключающее ИЛИ ~ Дополнение до единицы << Сдвиг влево >> Сдвиг вправо

Все операторы из таблицы 4.2, за исключением оператора дополнения до единицы (~), являются бинарными операторами, то есть предполагают два опе-ранда. Битовые операции можно выполнять с любым типом целого значения, но нельзя выполнять для значений с плавающей точкой. Побитовый оператор И

Если два значения связаны оператором И (&), то двоичные представления этих значений сравниваются бит за битом. Если какой-либо бит первого значения равен 1 и соответствующий бит второго значения равен 1, то соответствующий бит результата равен 1; во всех остальных случаях результат равен 0. Пусть b1 и b2 представляют соответствующие биты в двух операндах. В следующей таблице, которая называется таблицей истинности (truth table), представлены результаты операции И для всех возможных значений b1 и b2. b1 b2 b1 & b2 0 0 0 0 1 0 1 0 0 1 1 1

Например, если w1 и w2 определены с типом short int, w1 присвоено шестнадцатеричное значение 15 и w2 присвоено шестнадцатеричное значение Ос, то в результате следующего оператора переменной w3 присваивается значение 0x04: w3 = w1 & w2;

Чтобы разобраться в этом, нужно представить значения w1, w2 и w3 в виде двоичных чисел. Предполагается, что мы работаем с размером типа short int в 16 бит. w1 0000 0000 0001 0101 0x15 w2 0000 0000 0000 1100 & 0x0c – w3 0000 0000 0000 0100 0x04

Побитовые операции И часто используются для операций маскирования. Этот оператор можно использовать, чтобы задавать нулевые значения для оп-ределенных битов элемента данных. Например, в следующей строке переменной w3 присваивается результат применения операции И к переменной w1 и константе 3. w3 = w1 & 3;

В результате все биты w3, кроме двух правых битов, становятся равными 0, а два правых бита берутся из w1.

Как и для всех бинарных арифметических операторов в Objective-C, бинарные битовые операторы можно использовать как операторы присваивания, добавляя знак равенства. Например, строка word &= 15;

дает такой же результат, как word = word & 15;

то есть присваивает значение 0 всем битам переменной word, кроме четырех правых битов. Оператор побитового включающего ИЛИ

Если два значения связываются операцией побитового включающего ИЛИ (Inclusive-OR) в Objective-C, то происходит сравнение этих двух значений бит за битом. Но на этот раз, если бит первого значения равен 1 или соответствующий бит второго значения равен 1, то соответствующий бит результата равен 1. Ниже показана таблица истинности для оператора включающего ИЛИ. b1 b2 b1 | b2 0 0 0 0 1 1 1 0 1 1 1 1

Если переменным w1 и w2 типа short int присвоены соответственно шестнадцатеричные значения 19 и 6а, то операция включающего ИЛИ, примененная к w1 и w2, даст в результате шестнадцатеричное значение 7Ь, как показано ниже. w1 0000 0000 0001 1001 0x19 w2 0000 0000 0110 1010 | 0x6а – 0000 0000 0111 1011 0x7b

Эта операция часто используется, чтобы задавать определенные биты слова равными 1. Например, в следующей строке три правых бита переменной w1 за-даются равными 1 независимо от состояния этих битов до выполнения операции. w1 = w1 | 07;

Вместо этой строки можно написать оператор присваивания: w1 |= 07;

Далее мы приведем пример программы с оператором включающего ИЛИ. Оператор побитового исключающего ИЛИ

Оператор побитового исключающего ИЛИ (Exclusive-OR), или оператор XOR, действует следующим образом: если один из соответствующих битов двух опе-рандов равен 1 (но не оба), то соответствующий бит результата равен 1; в про-тивном случае он равен 0. Ниже приводится таблица истинности для этого оператора. b1 b2 b1 ^ b2 0 0 0 0 1 1 1 0 1 1 1 0

Если для w1 и w2 заданы соответственно шестнадцатеричные значения 5е и d6, то операция исключающего ИЛИ, примененная к w1 и w2, даст в результате шестнадцатеричное значение е8, как показано ниже. w1 0000 0000 0101 1110 0х5е w2 0000 0000 1011 0110 ^ 0xd6 – 0000 0000 1110 1000 0хе8 Оператор дополнения до единицы

Оператор дополнения до единицы (ones complement) – это унарный оператор, который меняет биты операнда на противоположные. Каждый бит, равный 1, изменяется на 0, и каждый бит, равный 0, изменяется на 1. Таблица истинности приводится здесь просто для полноты изложения. b1 ~b1 0 1 1 0

Если переменная w1 имеет тип short int, имеет длину 16 бит и для нее задано шестнадцатеричное значение a52f, то применение к этому значению операции дополнения до единицы даст в результате шестнадцатеричное значение 5аb0. w1 1010 0101 0010 1111 0xa52f ~w1 0101 1010 1101 0000 0x5ab0

Операцию дополнения до единицы полезно использовать, если вы не знаете размера в битах значения, к которому применяется какая-либо операция, и его использование может сделать программу менее зависимой от конкретного размера целого типа данных. Например, чтобы задать значение 0 для младшего бита переменной w1 типа int, можно применить операцию И к w1 и переменной типа int, содержащей все единицы, за исключением 0 в крайнем правом бите. Следующую строку на С можно применить на машинах, где целое значение представляется 32 битами: w1 &= OxFFFFFFFE;

Если заменить ее следующей строкой, то операция И будет применена к w1 и нужному значению на любой машине. w1 &=~1;

Операция дополнения до единицы, примененная к значению 1, даст 0 в край-нем правом бите, а все остальные биты слева будут равны 1 для значения типа любой длины (31 левый бит для 32-битных целых значений).

Приведем пример конкретной программы, где показано использование раз-личных битовых операторов. // Примеры битовых операторов #import int main (int argc, char *argv[]) { NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; unsigned int w1 = OxAOAOAOAO, w2 = OxFFFFOOOO, w3 = 0x00007777; NSLog (@"%x %x %x", w1 & w2, w1 | w2, w1 Л w2); NSLog (@"%x %x %x", ~w1, ~w2, ~w3); NSLog (@"%x %x %x", w1 л w1, w1 & ~w2, w1 | w2 | w3); NSLog (@"%x %х", w1 | w2 & w3, w1 | w2 & ~w3); NSLog (@"%x %x", ~(~w1 & ~w2), ~(~w1 | ~w2)); [pool drain]; return 0; }

Вывод программы 4.7 a0a00000 ffffaOaO 5f5fa0a0 5f5f5f5f ffff ffff8888 0 aOaO fffff7f7 aOaOaOaO ffffaOaO ffffaOaO aOaOOOOO

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

В четвертом вызове NSLog важно отметить, что побитовый оператор И имеет более высокий приоритет, чем побитовый оператор ИЛИ. Сводку приоритетов операторов см. в приложении В.

В пятом вызове NSLog иллюстрируется правило ДеМоргана: ~(~а & ~Ь) равно а | Ь, и ~(~а | ~Ь) равно а & Ь. Последовательность операторов показывает, что операция обмена действует так, как описано в разделе по оператору исключающего ИЛИ. Оператор левого сдвига

Если к значению применяется операция левого сдвига, то биты этого значения буквально сдвигаются влево. Для этой операции указывается число позиций (битов), на которое должно быть сдвинуто значение. Биты, которые выходят за старший бит элемента данных, утрачиваются, а младшие биты значения заме-щаются нулями. Например, если значение w1 равно 3, то выражение w1 = w1 << 1;

которое можно также представить как w1 <<= 1;

даст в результате смещение 3 на одну позицию влево, то есть w1 будет присвоено значение 6: w1 ...00000011 0x03 w1 << 1 ...00000110 0x06

Операнд слева от оператора « – это значение, к которому применяется сдвиг, а оператор справа – это количество битовых позиций, на которое должно быть сдвинуто значение. Например, если сдвинуть w1 еще на одну позицию влево, то мы получим шестнадцатеричное значение 0с. w1 ...00000110 0x06 w1 << 1 ...00001100 0х0с Оператор правого сдвига

Как следует из этого названия, оператор правого сдвига » смещает биты значения вправо. Биты, смещаемые за позицию младшего бита, теряются. Смещение вправо значения без знака (unsigned) приводит к замещению нулями старших битов. Замещение левой позиции для значений со знаком (signed) зависит от знака смещаемого вправо значения, а также от реализации этой операции в вашей компьютерной системе. Если бит знака равен 0 (для положительного значения), то происходит замещение нулями независимо от используемой машины. Но если бит знака равен 1, то на некоторых машинах происходит замещение единицами, а на других машинах – нулями. Первый тип операции называется арифметическим правым сдвигом, а второй тип – логическим правым сдвигом.

Внимание. Никогда не делайте предположений о типе правого сдвига (арифме-тическом или логическом), реализуемом в вашей системе. Программа, которая выполняет правый сдвиг значений со знаком, может работать правильно на одном компьютере и давать сбой на другом.

Если переменная w1 имеет тип unsigned int, представленный 32 битами, и w1 присвоено шестнадцатеричное значение F777EE22, то смещение w1 на одну по-зицию вправо с помощью оператора w1 >>= 1;

даст в результате шестнадцатеричное значение 7BBBF711, как показано ниже. w1 1111 0111 0111 0111 1110 1110 0010 0010 0xF777EE22 w1 >> 1 0111 1011 1011 1011 1111 0111 0001 0001 0x7BBBF711

Если w1 объявлена как (signed) short int, то на некоторых компьютерах будет получен тот же результат, а на других будет получено значение FBBBF711, если операция выполняется как арифметический правый сдвиг.

Если выполняется сдвиг значения влево или вправо на число позиций, равное или превышающее количество бит этого значения, то Objective-C не дает определенный результат. Например, на машине, представляющей целое значение 32 битами, сдвиг целого значения влево или вправо на 32 или больше битов не обязательно даст определенный результат. Если указана отрицательная величина смещения, то результат тоже неопределенный. 4.6. Типы: _Bool, .Complex и .Imaginary

Завершая эту главу, упомянем еще три типа: _Bool, для работы с булевыми зна-чениями (0 или 1), .Complex и .Imaginary – для работы с комплексными и мнимы-ми числами соответственно.


    Ваша оценка произведения:

Популярные книги за неделю