Г. Шилдт - С#4.0 Полное руководство (1160795), страница 17
Текст из файла (страница 17)
А если объявить переменную в конце блока, то она окажется, по существу, бесполезной, поскольку не будет доступной ни одному коду. Если в объявление переменной включается инициализатор, то такая переменная инициализируется повторно при каждом входе в тот блок, в котором она обьявлена. Рассмотрим следующий пример программы. Продемонстрировать время сушествования переменной. цвгпЧ Зувтеш; с1авв уаг1пьтбешо ( всаггс яотб Маьп() ( ьпв хг Гог(х = 0) х < Зг х++) ( ьпт у = -1) // Переменная у инициализируется при каждом входе в блок. Сопво1е.мг1сеь1пе("у равно: " + у)г // Здесь всегда выводится -1 у = 100г Сопво1е,ыгьгеььпе("у теперь равно: " + у)г Ниже приведен результат выполнения этой программы. Как видите, переменная у повторно инициализируется одним и тем же значением -1 при каждом входе во внутренний цикл гог.
И несмотря на то, что после этого цикла ей присваивается значение 1 О О, оно теряется при повторной ее инициализации. В языке С() имеется еще одна особенность соблюдения правил области действия; несмотря на то, что блоки могут быть вложены, ни у одной из переменных из внутренней области действия не должно быть такое же имя, как и у переменной из внешней области действия.
В приведенном ниже примере программы предпринимается попытка объявить две разные переменные с одним и тем же именем, и поэтому программа не может быть скомпилирована. /* В этой программе предпринимается попытка объявить во внутренней области действия переменную с таким же самым именем, как и у переменной, определенной во внешней области действия. у равно: у теперь у равно: у теперь у равно: у теперь — 1 равно: 100 -1 равно: 100 -1 равно: 100 Гяава 3. Типы данных, литералы и переменные 89 *** Эта программа не может быть скомпилирована.
*** */ ця1пЧ Буявеш! с1аяя Неяпуаг ( ясаь1с чогб Мага(! гпь соцпш гог(соцпг = 0; соцпг < 10; соцпь = сопля+1! ( Сопяо1е.нгьпеьтпе("Это подсчет: " + соцпа( 1пс соцпс! // Недопустимо!!! Гог(сопла = О; соцпв < 2; соцпсьь( Сопяо1е.иггвеь1пе("В этой программе есть ошибка!"); ! ! ! Если у вас имеется некоторый опьп программирования на С или С++, то вам должно быть известно, что на присваивание имен переменным, объявляемым во внутренней области действия, в этих языках не существует никаких ограничений. Следовательно, в.С и С н- объявление переменной соцпс в кодовом блоке, входящем во внешний цикл 1ог, как в приведенном выше примере, считается вполне допустимым. Но в С и С++ такое объявление одновременно означает сокрытие внешней переменной.
Разработчики Са посчитали, что такого рода сокрытие имен может легко привести к программным ошибкам, и поэтому решили запретить его. Преобразование и приведениетипов В программировании нередко значения переменных одного типа присваиваются переменным другого типа. Например, в приведенном ниже фрагменте кода целое значение типа 1пс присваивается переменной с плавающей точкой типа Воас. !(оас г( 10; Г = г( // присвоить целое значение переменной типа Поаг Если в одной операции присваивания смешиваются совместимые типы данных, то значение в правой части оператора присваивания автоматически преобразуется в тип, указанный в левой его части.
Поэтому в приведенном выше фрагменте кода значение переменной 1 сначала преобразуется в тип ((оас, а затем присваивается переменной 1. Но вследствие строгого контроля типов далеко не все типы данных в С(( оказываются полностью совместимыми, а следовательно, не все преобразования типов разрешены в неявном виде.
Например, типы Ьоо1 и 1пс несовместимы. Правда, преобразование несовместимых типов все-таки может быть осуществлено путем приведения, Приведение типов, по существу, означает явное их преобразование. В этом разделе рассматривается как автоматическое преобразование, так и приведение типов.
90 Часть (. Язык С№ Автоматическое преобразоваииетипов Когда данные одного типа присваиваются переменной друпзго типа, неявное преобразование типов происходит автоматически при следующих условиях: ° оба типа совместимы; ° диапазон представления чисел целевого типа шире, чем у исходного типа. Если оба эти условия удовлетворяются, то происходи г расширяющее пршбразование. Например, тип Ьпс достаточно крупный, чтобы вмещать в себя все действительные значения типа Ьусе, а кроме того, оба типа, 1пс и Ьусе, являются совместимыми целочисленными типами, и поэтому для них вполне возможно неявное преобразование. Числовые типы, как целочисленные, так и с плавающей точкой, вполне совместимы друг с другом для выполнения расширяющих преобразований.
Так, приведенная ниже программа составлена совершенно правильно, поскольку преобразование типа 1оп9 в тип с(опЬ1е является расширяющим и выполняется автоматически. Продемонстрировать неявное преобразование типа 1оп9 в тип аооЬ1е. ояьп9 Буясеьн с1азз Ьгоо ( ясагьс уо1с( Маьп() ( 1оп9 Ь; бооЬ1е О) Ь = 1001232В5Ь( О = Ье Сопяо1е.игггеььпе("Ь и О: " + 1. Е " " Е О); Если тип 1оп9 может быть преобразован в тип с(опЬ1е неявно, то обратное преобразование типа г(опЬ1е в тип 1оп9 неявным образом невозможно, поскольку оно не является расширяющим.
Следовательно, приведенный ниже вариант предыдущей программы составлен неправильно. // *** Эта программа не может быть скомпипирована. *** оз1п9 Зуясевн с1аяя Ьгоо ( зоаг1с уо1б Ма1п() ( 1оп9 Гн г)ооЬ1е О; О = 100123285.0; Ь = О; // Недопустимо!!! Сопзо1е.нггоеььпе("Ь и О: " ь 1. е " " т О); Помимо упомянутых выше ограничений, не допускается неявное взаимное преобразование типов с)ес1ма1 и ((оаг или г(опЬ1е, а также числовых типов и сЬаг или Ьоо1. Кроме того, типы снап и Ьоо1 несовместимы друг с другом. Глава 3.
Типы данных, литералы и переменные 9з. Приведение несовместимыхтипов Несмотря на всю полезность неявных преобразований типов, они неспособны удовлетворить все потребности в программировании, поскольку допускают лишь расширяющие преобразования совмесгимььх типов. А во всех остальных случаях приходится обращаться к приведению типов.
Приведение — это команда компилятору преобразовать результат вычисления выражения в указанный тип. А для этого требуется явное преобразование типов. Ниже приведена общая форма приведения типов. (целевой тиц( вмражения Здесь целевой тип обозначает тот тип, в который желательно преобразовать указанное выражение.
Рассмотрим для примера следующее объявление переменных. бсць1е х, у; Если результат вычисления выражения х/у должен быть типа Тпс, то следует записать следующее. (х / у( Несмотря на то что переменные х и у относятся к типу боцЬ1е, результат вычисления выражения х у у преобразуется в тип 1пс благодаря приведению. В данном примере выражение хду следует непременно указывать в скобках, иначе приведение к типу ьпс будет распространяться только на переменную х, а не на результат ее деления на переменную у. Приведение типов в данном случае требуется потому, что неявное преобразование типа боцЬ1е в тип 1ПС невозможно. Если приведение типов приводит к сужаюи(ему преобразованию, то часть информации может быть потеряна. Например, в результате приведения типа 1опгг к типу ьпг часть информации потеряется, если значение типа 1оп3 окажется больше диапазона представления чисел для типа лпь, поскольку старшие разряды этого числового значения отбрасываются. Когда же значение с плавающей точкой приводится к целочисленному, то в результате усечения теряется дробная часть этого числового значения.
Так, если присвоить значение 1,23 целочисленной переменной, то в результате в ней останется лишь целая часть исходного числа (1), а дробная его часть (0,23) будет потеряна. В следующем примере программы демонстрируется ряд преобразований типов, требующих приведения. В этом примере показан также ряд ситуаций, в которых приведение типов становится причиной потери данных. Х/ Продемонстрировать приведение типов. цяьцц Буяседо с1аяя СаяСОеис ясаььс чсгб Иаьц (( бсцЬ1е х, у; ьгсе ь! гпс хг сьаг сь; цгцс цг яьсгс я; 1спд 1 х = 10.0г 92 Часть!.
Язык С() у = 3.0; // Приведение типа бопЬ1е к типу гпГ, дробная часть числа теряется. — (тпг) (х / у); сопзо1е.хггсеььпе("целочисленный результат деления х / у: " ь 1)) Сопво1е.иг11еьгпе()4 // Приведение типа 1пг к типу Ьусе без потери данных. — 255; Ь = (Ьуге) 1) Сопво1е.аггсе11пе("Ь после присваивания 255: " + Ь вЂ” без потери данных."); // Приведение типа тпг к типу Ьусе с потерей данных. 257; Ь = (Ьусе) Сопзо1е.иг1Ге11пе("Ь после присваивания 257: " + Ь с потерей данных."); Сопво1е.нг1Геь1пе(); Приведение типа птпс к типу вЬогГ без потери данных.
о = 32000; в = (вьогг) и; сопво1е.хг1геьгпе("в после присваивания 32000: в + " — без потери данных."); // Приведение типа п1пг к типу зЬогс с потерей данных. и = 640004 з = (алого) и; сопзо1е.аг1геь1пе("а после присваивания 64000". в ь " -- с потерей данных."); Солзс1Е.ИГ1ГЕЬ1ПЕ()4 // Приведение типа 1опц к типу дыло без потери данных. — 640004 и = (пьпс) 1; сопво1е.игьгеььпе("о после присваивания 64000: " + ч + без потери данных."); // Приведение типа 1опд к типу ньпс с потерей данных. 1 = -12; ч = (пгпс) 1; Сопао1е.нггсеььпе("о после присваивания -12: " + о + с потерей данных."); Сопво1е.ыгтсеьгпе(); // Приведение типа ьпс к типу слаг.
Ь = 88; // код АЯС11 символа Х сЬ = (сЬаг) Ьг Сопао1е.ыгагеь1пе("сЬ после присваивания 88: " + сЬ)4 ) ) Вот какой результат дает выполнение этой программы. Целочисленный результат деления х / у: 3 Ь после присваивания 255: 255 -- без потери данных. Глава 3. Типы данных, литералы и переменные ЕЗ Ь после присваивания 257: 1 -- с потерей данных.
в после присваивания 32000: 32000 -- без потери данных. в после присваивания 64000: -1536 -- с потерей данных. и после. присваивания 64000: 64000 -- бев потери данных. о после присваивания -12: 4294967284 -- с потерей данных. сЬ после присваивания 88: Х Рассмотрим каждую операцию присваивания в представленном выше примере программы по отдельности. Вследствие приведения результата деления х/у к типу ьпс отбрасывается дробная часть числа, а следовательно, теряется часть информации.