Daniel_Cortez
01.04.2016, 11:11
Всем привет. У вас спина белая.
Нередко мне приходилось сталкиваться на просторах форума с фразами типа "массив char", как будто это какой-то особенный вид массивов.
В данном уроке я постараюсь рассмотреть несколько вопросов по оператору char, по которым у новичков чаще всего возникают заблуждения:
Чем массивы, объявленные с "char" в размере, отличаются от других массивов? Чем отличается их использование?
Для чего предназначено слово "char"? Оно означает какой-то тип данных?
Т.е. чтобы получить нужное кол-во ячеек, достаточно разделить число байт на размер ячейки в байтах (4)? Тогда зачем вообще нужен оператор char, если можно просто делить на 4?
Итак, начнём разбор полётов:
1. Чем массивы, объявленные с "char" в размере, отличаются от других массивов? Чем отличается их использование?
Оператор char влияет лишь на размер массива. Массивы, в размере которых используется char, ничем принципиально не отличаются от других массивов.
Например, можно объявить массив с указанием char в размере, а потом читать/записывать данные в его ячейки, а не в отдельные байты.
new a[12 char]; // "char" означает, что в массиве должно быть достаточно ячеек, чтобы уместить 12 байт.
// i примет значения от 0 до 12 / 4 - 1 = 2,
// где 4 - размер ячейки в байтах.
for (new i = 0; i < sizeof(a); ++i)
a[i] = i;
Также можно объявить массив без char в размере, но записывать значения в отдельные байты массива:
new a[5]; // В массиве 5 ячеек или 5 * 4 = 20 байт
// В стандартной константе "cellbits" находится количество бит в ячейке, в "charbits" - бит в байте.
// Количество байт в ячейке можно получить с помощью выражения "cellbits / charbits".
for (new i = 0; i < sizeof(a) * cellbits / charbits; ++i)
a{i} = i;
Как видите, оператор char абсолютно не влияет на правила обращения с массивом.
Читать и записывать значения в отдельные байты массива можно даже если в указании его размера не используется char. Главное не словить выход за пределы массива.
2. Для чего предназначено слово "char"? Оно означает какой-то тип данных?
Во-первых, это не тип данных, а оператор.
Это довольно распространённое заблуждение о том, что char означает тип данных размером в 1 байт и нужно пользоваться им для экономии памяти, но в Pawn любые данные занимают 1 ячейку. Кроме того, как уже было сказано выше, char не меняет правил использования массивов.
Во-вторых, оператор char нужен для того, чтобы узнать, сколько ячеек потребуется для того, чтобы вместить определённое количество байт.
Например, при размере ячейки в 4 байта, чтобы вместить 12 байт, нужны 3 ячейки.
И да, применение оператора не ограничено одними лишь массивами:
printf("Для хранения %d байт нужно %d ячеек", 12, 12 char);
Ещё пример, на этот раз с константой:
const NUM_BYTES = 12;
const ARRAY_SIZE = NUM_BYTES char;
new a[ARRAY_SIZE];
3. Т.е. чтобы получить нужное кол-во ячеек, достаточно разделить число байт на размер ячейки в байтах (4)? Тогда зачем вообще нужен оператор char, если можно просто делить на 4?
Всё немного сложнее, чем кажется. Начнём с того, что недостаточно просто разделить на 4.
Допустим, у нас есть не 12, а 14 байт. 14 / 4 = 3 ячейки. Но три ячейки хватит только на 3 * 4 = 12 байт, а ещё 2 байта не вместятся.
Иными словами, при простом делении на 4 не учитывается остаток от деления.
Оператор char работает следующим образом: перед делением к кол-ву байт добавляется максимально возможный остаток от деления (в данном случае при делении на 4 максимальный остаток - 3).
Таким образом получаем примерную формулу:
X char = (X + 3) / 4
Проверка: (14 + 3) / 4 = 17 / 4 = 4. Четырёх ячеек как раз хватит, чтобы сохранить 14 байт.
Даже останется место ещё для двух байт, но мы же не можем выделить три с половиной ячейки - только целое количество.
Кроме того, в разных вариантах Pawn размер ячейки может быть не только 4, но и 2 или 8 байт.
А потому утвердждение "в 1 ячейке 4 байта" справедливо только для SA:MP и некоторых других приложений/игр, в которых в Pawn установлен именно четырёхбайтовый размер ячеек.
Например, 8 байт на ячейку можно встретить в проекте VaultMP (http://www.vaultmp.com/), а при 8-байтном размере ячейки будет неправильно делить кол-во байт на 4.
Для решения подобных проблем компилятор предоставляет константы cellbits и charbits, о которых уже было написано выше.
Разделив кол-во бит в ячейке на кол-во бит в байте можно получить кол-во байт в ячейке.
В итоге работу оператора char можно описать следующей формулой:
X char = (X + cellbits / charbits - 1) / (cellbits / charbits)
Как вы можете заметить, эта формула совершенно не похожа на простое деление на 4.
Итак, на сегодня всё. Если у вас есть ещё вопросы по теме, буду рад их выслушать в комментариях.
Автор: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)
Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!
Нередко мне приходилось сталкиваться на просторах форума с фразами типа "массив char", как будто это какой-то особенный вид массивов.
В данном уроке я постараюсь рассмотреть несколько вопросов по оператору char, по которым у новичков чаще всего возникают заблуждения:
Чем массивы, объявленные с "char" в размере, отличаются от других массивов? Чем отличается их использование?
Для чего предназначено слово "char"? Оно означает какой-то тип данных?
Т.е. чтобы получить нужное кол-во ячеек, достаточно разделить число байт на размер ячейки в байтах (4)? Тогда зачем вообще нужен оператор char, если можно просто делить на 4?
Итак, начнём разбор полётов:
1. Чем массивы, объявленные с "char" в размере, отличаются от других массивов? Чем отличается их использование?
Оператор char влияет лишь на размер массива. Массивы, в размере которых используется char, ничем принципиально не отличаются от других массивов.
Например, можно объявить массив с указанием char в размере, а потом читать/записывать данные в его ячейки, а не в отдельные байты.
new a[12 char]; // "char" означает, что в массиве должно быть достаточно ячеек, чтобы уместить 12 байт.
// i примет значения от 0 до 12 / 4 - 1 = 2,
// где 4 - размер ячейки в байтах.
for (new i = 0; i < sizeof(a); ++i)
a[i] = i;
Также можно объявить массив без char в размере, но записывать значения в отдельные байты массива:
new a[5]; // В массиве 5 ячеек или 5 * 4 = 20 байт
// В стандартной константе "cellbits" находится количество бит в ячейке, в "charbits" - бит в байте.
// Количество байт в ячейке можно получить с помощью выражения "cellbits / charbits".
for (new i = 0; i < sizeof(a) * cellbits / charbits; ++i)
a{i} = i;
Как видите, оператор char абсолютно не влияет на правила обращения с массивом.
Читать и записывать значения в отдельные байты массива можно даже если в указании его размера не используется char. Главное не словить выход за пределы массива.
2. Для чего предназначено слово "char"? Оно означает какой-то тип данных?
Во-первых, это не тип данных, а оператор.
Это довольно распространённое заблуждение о том, что char означает тип данных размером в 1 байт и нужно пользоваться им для экономии памяти, но в Pawn любые данные занимают 1 ячейку. Кроме того, как уже было сказано выше, char не меняет правил использования массивов.
Во-вторых, оператор char нужен для того, чтобы узнать, сколько ячеек потребуется для того, чтобы вместить определённое количество байт.
Например, при размере ячейки в 4 байта, чтобы вместить 12 байт, нужны 3 ячейки.
И да, применение оператора не ограничено одними лишь массивами:
printf("Для хранения %d байт нужно %d ячеек", 12, 12 char);
Ещё пример, на этот раз с константой:
const NUM_BYTES = 12;
const ARRAY_SIZE = NUM_BYTES char;
new a[ARRAY_SIZE];
3. Т.е. чтобы получить нужное кол-во ячеек, достаточно разделить число байт на размер ячейки в байтах (4)? Тогда зачем вообще нужен оператор char, если можно просто делить на 4?
Всё немного сложнее, чем кажется. Начнём с того, что недостаточно просто разделить на 4.
Допустим, у нас есть не 12, а 14 байт. 14 / 4 = 3 ячейки. Но три ячейки хватит только на 3 * 4 = 12 байт, а ещё 2 байта не вместятся.
Иными словами, при простом делении на 4 не учитывается остаток от деления.
Оператор char работает следующим образом: перед делением к кол-ву байт добавляется максимально возможный остаток от деления (в данном случае при делении на 4 максимальный остаток - 3).
Таким образом получаем примерную формулу:
X char = (X + 3) / 4
Проверка: (14 + 3) / 4 = 17 / 4 = 4. Четырёх ячеек как раз хватит, чтобы сохранить 14 байт.
Даже останется место ещё для двух байт, но мы же не можем выделить три с половиной ячейки - только целое количество.
Кроме того, в разных вариантах Pawn размер ячейки может быть не только 4, но и 2 или 8 байт.
А потому утвердждение "в 1 ячейке 4 байта" справедливо только для SA:MP и некоторых других приложений/игр, в которых в Pawn установлен именно четырёхбайтовый размер ячеек.
Например, 8 байт на ячейку можно встретить в проекте VaultMP (http://www.vaultmp.com/), а при 8-байтном размере ячейки будет неправильно делить кол-во байт на 4.
Для решения подобных проблем компилятор предоставляет константы cellbits и charbits, о которых уже было написано выше.
Разделив кол-во бит в ячейке на кол-во бит в байте можно получить кол-во байт в ячейке.
В итоге работу оператора char можно описать следующей формулой:
X char = (X + cellbits / charbits - 1) / (cellbits / charbits)
Как вы можете заметить, эта формула совершенно не похожа на простое деление на 4.
Итак, на сегодня всё. Если у вас есть ещё вопросы по теме, буду рад их выслушать в комментариях.
Автор: Daniel_Cortez (http://pro-pawn.ru/member.php?100-Daniel_Cortez)
Специально для Pro-Pawn.ru (http://www.pro-pawn.ru)
Копирование данной статьи на других ресурсах без разрешения автора запрещено!