Как пишется != как хранится != как интерпретируется 🙈
Разбавлю немного ОО тематику последних постов. Одной из самых мозговзрывающих концепций, для начинающих в мире Computer Science - это то, как данные хранятся в памяти и как они выводятся нам на экран.
В чем же тут подвох? А дело в том, что нет абсолютно никакой зависимости между тем, что мы видим на экране и тем как оно представлено в памяти. Но нам, по началу, интуитивно хочется, чтобы связь все таки была.
Приведу пример. В JS мы можем задать числовой тип используя множество различных литеральных форм. Формы отличаются используемой системой счисления: двоичная, восьмеричная, десятичная и шестнадцатеричная. Более того, используя функцию
На самом деле, во всех представленных примерах задано одно и то же число, но в разных системах счисления. Вообще, система счисления просто определяет как записать то или иное число. И для человека является наиболее привычной именно десятичная (10 пальцев на руках).
А вот для задач информатики удобнее использовать другие системы. Но влияет ли это на что-то, кроме того, как мы записываем число? И тут ответ - в большинстве ЯП однозначно нет.
В JS у нас два явных числовых типа: Number (число с плавающей точкой размером 64 бита) и BigInt (целое безразмерное знаковое число). Под капотом, VM могут вводить дополнительные числовые типы, например, SMI для хранения целых знаковых чисел не превышающих 2 ** 31.
А значит, я могу точно сказать, что
Хорошо, но почему тогда отладчик число
Порефлексируем. То, что мы видим в отладчике не является байтовым представлением самих данных, а "рендерингом" этих данных в наиболее удобном нам формате. При этом визуально идентичные в отладчике данные могут храниться по-разному в памяти.
Приведу пример на Rust. Просто объявим несколько переменных содержащий с точки зрения человека одинаковые данные, но имеющие разный тип. И напишем функцию рендеринга этих значений в "бинарном виде": функция будет создавать строку, которая будет максимально близко с визуальной точки зрения показывать, как же в памяти хранятся наши типы.
Можем видеть, что число 10 одинаково представлено в памяти для u8 и i8, а вот уже для других типов значение отличается.
А также видим, что выведение данных в отладчик является процессом интерпретации. Вот мы смотрим на байты и представляем их как десятичные числа, а вот как просто поток нулей и единиц.
Разбавлю немного ОО тематику последних постов. Одной из самых мозговзрывающих концепций, для начинающих в мире Computer Science - это то, как данные хранятся в памяти и как они выводятся нам на экран.
В чем же тут подвох? А дело в том, что нет абсолютно никакой зависимости между тем, что мы видим на экране и тем как оно представлено в памяти. Но нам, по началу, интуитивно хочется, чтобы связь все таки была.
Приведу пример. В JS мы можем задать числовой тип используя множество различных литеральных форм. Формы отличаются используемой системой счисления: двоичная, восьмеричная, десятичная и шестнадцатеричная. Более того, используя функцию
parseInt
мы можем добавить поддержку записи до 36-тиричной системы счисления.console.log( 0b10000000000 );
console.log( 0o2000 );
console.log( 1024 );
console.log( 0x400 );
console.log( parseInt('SG', 36) );
На самом деле, во всех представленных примерах задано одно и то же число, но в разных системах счисления. Вообще, система счисления просто определяет как записать то или иное число. И для человека является наиболее привычной именно десятичная (10 пальцев на руках).
А вот для задач информатики удобнее использовать другие системы. Но влияет ли это на что-то, кроме того, как мы записываем число? И тут ответ - в большинстве ЯП однозначно нет.
В JS у нас два явных числовых типа: Number (число с плавающей точкой размером 64 бита) и BigInt (целое безразмерное знаковое число). Под капотом, VM могут вводить дополнительные числовые типы, например, SMI для хранения целых знаковых чисел не превышающих 2 ** 31.
А значит, я могу точно сказать, что
0b101 === 5
. Оба эти литерала представляются типом Number, который абсолютно одинаково хранится в памяти.Хорошо, но почему тогда отладчик число
0b101
всегда выводит как 5
? А дело в том, что отладчик выводит значение типа в максимальной удобной для восприятия человеком, а так как у нас тут число, то логично использовать десятичную систему счисления. Более того, сам вывод на экран подразумевает следующую операцию: нам необходимо преобразовать байты числа в формат строки в соответствии с используемой кодировкой или таблицей символов; затем "отрендерить" эту строку на экране используя специальную схему визуализации - "шрифт" и библиотеку рендеринга шрифтов, например, DirectWrite (за нас это, как правило, делает ОС или другое окружение).Порефлексируем. То, что мы видим в отладчике не является байтовым представлением самих данных, а "рендерингом" этих данных в наиболее удобном нам формате. При этом визуально идентичные в отладчике данные могут храниться по-разному в памяти.
Приведу пример на Rust. Просто объявим несколько переменных содержащий с точки зрения человека одинаковые данные, но имеющие разный тип. И напишем функцию рендеринга этих значений в "бинарном виде": функция будет создавать строку, которая будет максимально близко с визуальной точки зрения показывать, как же в памяти хранятся наши типы.
fn main() {
let a: u8 = 10;
let b: i8 = 10;
let c: u16 = 10;
let d: f32 = 10.0;
print_bytes_in_binary(&a.to_ne_bytes()); // 00001010
print_bytes_in_binary(&b.to_ne_bytes()); // 00001010
print_bytes_in_binary(&c.to_ne_bytes()); // 0000101000000000
print_bytes_in_binary(&d.to_ne_bytes()); // 00000000000000000010000001000001
}
fn print_bytes_in_binary(bytes: &[u8]) {
let mut res = String::new();
for byte in bytes {
res += &format!("{:08b}", byte)
}
println!("{:?}", res);
}
Можем видеть, что число 10 одинаково представлено в памяти для u8 и i8, а вот уже для других типов значение отличается.
А также видим, что выведение данных в отладчик является процессом интерпретации. Вот мы смотрим на байты и представляем их как десятичные числа, а вот как просто поток нулей и единиц.