Символьный тип


Значением символьного типа char являются символы из некоторого предопределенного множества. В большинстве современных персональных ЭВМ этим множеством является ASCII (American Standard Code for Information Intechange - американский стандартный код для обмена информацией). Это множество состоит из 256 разных символов, упорядоченных определенным образом, и содержит символы заглавных и строчных букв, цифр и других символов, включая специальные управляющие символы. Допускаются некоторые отклонения от стандарта ASCII, в частности, при наличии соответствующей системной поддержки это множество может содержать буквы русского алфавита. Порядковые номера (кодировку) можно узнать в соответствующих разделах технических описаний.

Значение символьного типа char занимает в памяти 1 байт. Код от 0 до 255 в этом байте задает один из 256 возможных символов ASCII таблицы. Например: символ "1" имеет ASCII код 49, следовательно, машинное представление будет выглядеть следующим образом: 00110001.

ASCII, однако, не является единственно возможным множеством. Другим достаточно широко используемым множеством является код EBCDIC (Extended Binary Coded Decimal Interchange Code - расширенный двоично-кодированный десятичный код обмена), применяемый в системах IBM средней и большой мощности. В EBCDIC код символа также занимает один байт, но с иной кодировкой, чем в ASCII.

И ASCII, и EBCDIC включают в себя буквенные символы только латинского алфавита. Символы национальных алфавитов занимают "свободные места" в таблицах кодов, и, таким образом, одна таблица может поддерживать только один национальный алфавит. Этот недостаток преодолен во множестве UNICODE, которое находит все большее распространение прежде всего в UNIX-ориентированных системах. В UNICODE каждый символ кодируется двумя байтами, что обеспечивает более 64 тыс. (216) возможных кодовых комбинаций и дает возможность иметь единую таблицу кодов, включающую в себя все национальные алфавиты. UNICODE, безусловно, является перспективным, однако, повсеместный переход к двухбайтным кодам символов может вызвать необходимость переделки значительной части существующего программного обеспечения.

Специфические операции над символьными типами - только операции сравнения. При сравнении коды символов рассматриваются как целые числа без знака. Кодовые таблицы строятся так, что результаты сравнения подчиняются лексикографическим правилам: символы, занимающие в алфавите места с меньшими номерами, имеют меньшие коды, чем символы, занимающие места с большими номерами. В основном символьный тип данных используется как базовый для построения интегрированного типа "строка символов", рассматриваемого в гл.4.

 

 

Символы в C#

В отличие от других языков программирования (таких, как С++, в которых для представления символа выделяется 8 битов, что позволяет работать с 255 символами) в C# используется стандартный набор символов Unicode, в котором представлены символы всех языков мира. В C# char - беззнаковый тип, которому для представления данных выделено 16 битов, что позволяет работать со значениями, находящимися в диапазоне от 0 до 65535 (то есть с 65535-ю символами). Стандартный 8-битовый набор символов ASCII является составной частью Unicode и находится в диапазоне от 0 до 127. Таким образом, ASCII-символы остаются действительными в C#.

Для того чтобы присвоить значение символьной переменной, нужно заключить в одинарные кавычки символ, стоящий справа от оператора присваивания. Ниже показан синтаксис операторов, при выполнении которых переменной ch присваивается значение X.

char ch;
ch = 'X';

Для вывода символьного значения используется оператор WriteLine(). Следующая строка выводит значение переменной ch:

Console.WriteLine("Значение переменной ch - " + ch);

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

char ch;
ch = 10; // Данный оператор недействителен.

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

Далее в этой главе мы расскажем, как можно обойти это ограничение.

Вопрос.Почему в C# используется Unicode?
Ответ.В задачи разработчиков C# входило создание такого компьютерного языка, который позволял бы писать программы, предназначенные для использования во всем мире. Поэтому авторы воспользовались стандартным набором символов Unicode, в котором представлены все языки мира. Конечно, использование этого стандарта неэффективно для таких языков, как английский, немецкий, испанский или французский, символы которых могут быть представлены 8 битами, но это цена, которую приходится платить за переносимость программ в глобальном масштабе.

 

 

Символьный тип. C#.

Для хранения одного символа С# поддерживает тип данных char:

Имя Тип CTS Значения
char System.Char Представляет один символ Unicode (16 бит)

Хотя этот тип данных имеет сходство с типом данных char в С и С++, все же существует значительная разница.
Выше упоминалось, что неявные преобразования между типом char и 8-разрядным типом byte не разрешены. Это вызвано, в частности, тем, что типы имеют разные размеры — длина типа char составляет 16 бит.

Хотя для представления любого символа английского алфавита и цифр от 0 до 9 хватит восьми битов, этого недостаточно для представления символов в более объемных символьных системах (например, китайский язык). В целях обеспечения универсальности компьютерная индустрия движется от 8-битовых наборов символов к 16-битовой схеме Unicode, в которой кодировка ASCII является подмножеством.
Помните о том, что значения char являются 16-битовыми значениями Unicode, в частности тогда, когда вы будете обращаться к ним с помощью указателей в блоках небезопасного кода.
Константы типа char обозначаются одинарными кавычками, например ‘А’. Если заключить символ в двойные кавычки, компилятор посчитает ее строкой и сгенерирует ошибку.
Символы char можно представлять не только литералами, но и четырехзначными шестнадцатеричными значениями Unicode (например, ‘\u0041′), приведенными значениями целого типа (например, (char) 65) или шестнадцатеричными значениями (’\x0041′). Они могут содержать также последовательности специальных символов:

Последовательность специальных символов Значение
\’ Одинарная кавычка
\” Двойная кавычка
\\ Обратный слэш
\0 Null
Внимание
\b Возврат назад на один символ
\f Подача страницы
\n Новая строка
\r Возврат каретки
\t Символ табуляции
\v Вертикальная табуляция

Разработчики на С++ должны отметить для себя: поскольку С# имеет встроенный тип string, нет необходимости представлять строки массивами символов.

 

Преобразование типов в выражениях
В пределах выражения существует возможность совмещения двух и более различных типов данных при условии, что они являются совместимыми. Например, вы можете совмещать в выражении данные типа short и long, поскольку оба эти типа являются числовыми. Если в выражении совмещаются различные типы данных, они преобразуются в один и тот же тип на основе алгоритма пошагового преобразования (то есть в соответствии с приоритетностью выполнения операций).

Преобразования выполняются посредством использования принятых в C# правил автоматического преобразования типов в выражениях. Ниже представлен алгоритм, определенный этими правилами для арифметических операций.

Если один операнд имеет тип decimal, то второй операнд автоматически преобразуется к типу decimal (за исключением случаев, когда он имеет тип float или double; в этом случае произойдет ошибка).

Если один из операндов имеет тип double, второй операнд автоматически преобразуется к типу double.

Если один операнд имеет тип float, второй операнд автоматически преобразуется к типу float.

Если один операнд имеет тип ulong, второй операнд автоматически преобразуется к типу ulong (за исключением случаев, когда он имеет тип sbyte, short, int или long; в этих случаях произойдет ошибка).

Если один операнд имеет тип long, второй операнд автоматически преобразуется к типу long.

Если один операнд имеет тип uint, а второй операнд - тип sbyte, short или int, то оба операнда автоматически преобразуются к типу long.

Если один операнд имеет тип uint, второй операнд автоматически преобразуется к типу uint.

Если ни одно из вышеуказанных правил не применялось, оба операнда преобразуются к типу int.

Обратите внимание на некоторые моменты, касающиеся правил автоматического преобразования типов. Не все типы данных могут совмещаться в выражениях (в частности, невозможно автоматическое преобразование данных типа float или double в тип decimal и невозможно совмещение данных типа ulong с любым другим типом знаковых целочисленных данных). Совмещение этих типов требует использования операции явного приведения типа.

Внимательно прочитайте последнее правило, в котором говорится, что если ни одно из вышеперечисленных правил не применялось, то все операнды преобразуются к типу int. Следовательно, все значения, имеющие тип char, sbyte, byte, ushort и short, в выражении преобразуются к типу int для выполнения вычислений. Такая процедура называется автоматическим преобразованием к целочисленному типу. Это также означает, что результат всех математических операций будет иметь тип, которому для хранения значения выделено не меньше битов, чем типу int.

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

Учтите, что автоматическое преобразование типа может привести к неожиданному результату. Например, когда арифметическая операция проводится с двумя значениями типа byte, выполняется такая последовательность действий: вначале операнды byte преобразуются к типу int, а затем вычисляется выражение, результат которого тоже будет иметь тип int. Результат операции над двумя значениями byte будет иметь тип int. Это довольно неожиданное следствие выполнения вышеуказанного правила, поэтому программист должен контролировать тип переменной, которой будет присвоен результат. Применение правила автоматического преобразования к целочисленному типу рассматривается в следующей программе:

// В программе демонстрируется применение правила автоматического
// преобразования к целочисленному типу.

using System;

class PromDemo {
public static void Main() {
byte b;
int i;

b = 10;
i = b * b; // В данном случае не требуется явное приведение типа.

b = 10;
b = (byte) (b * b); // Тип результата должен быть приведен
// к типу переменной b.

Console.WriteLine("Значения переменных i и b: " + i + " " + b);
}
}

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

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

char ch1 = 'a', ch2 = 'b';
ch1 = (char) (ch1 + ch2);

Без приведения типа результат сложения значений переменных ch1 и ch2 имеет тип int и не может быть присвоен переменной типа char.

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

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

using System;

class UseCast {
public static void Main() {
int i;

for(i = 0; i < 5; i++) {
Console.WriteLine("Целочисленный результат вычисления выражения "
+i+"/3: " + i / 3);
Console.WriteLine("Результат вычисления выражения, выводимый" +
"с дробной частью: {0:#.##}",(double) i / 3);
Автоматическое преобразование типа значения из long в double.
Console.WriteLine();
}
}
}

Ниже показан результат выполнения этой программы:
Целочисленный результат вычисления выражения 0/3: 0
Результат вычисления выражения, выводимый с дробной частью:

Целочисленный результат вычисления выражения 1/3: 0
Результат вычисления выражения, выводимый с дробной частью: .33

Целочисленный результат вычисления выражения 2/3: 0
Результат вычисления выражения, выводимый с дробной частью: .67

Целочисленный результат вычисления выражения 3/3: 1
Результат вычисления выражения, выводимый с дробной частью: 1

Целочисленный результат вычисления выражения 4/3: 1
Результат вычисления выражения, выводимый с дробной частью: 1.33

Вопрос. Происходит ли преобразование типов в выражениях с унарными операторами, такими как унарный минус?
Ответ. Да. Для унарных операций операнды, у которых диапазон допустимых значений меньший, чем у int (такие, как byte, sbyte, short и ushort), преобразуются к типу int. Операнд типа char также преобразуется к типу int. Кроме того, если операнду типа uint присваивается отрицательное значение, он преобразуется к типу long.