Часто становится весьма непривычно, что нумерация начинается с 0 а не 1 и это немного сбивает, может быть программирование это не моё, раз меня такие простые вещи сбивают с толку, как к этому привыкнуть?
А выражение "времени третий час дня" не сбивает с толку, когда на часах 14:хх Или "на пятом десятке лет", когда человеку 4х лет? А "Восемнадцатый век", когда про 17хх год говорят? Это еще фигня, бывает бит 0 - старший, а 7 младший в байте.
Просто для нумерации битов используй тоже биты. Тогда восемь бит байта будут нумероваться по порядку комбинациями из трёх бит: 000 001 010 011 100 101 110 111 Теперь если раздавать им значащие имена, то слово "нулевой" появится само собой.
Если поработать с массивами в C или PHP, то в этих языках явно видно, что с 0 нумерация чаще. Ещё не всегда понятно, где последняя итерация в циклах, тоже интересная тема.
С нуля удобно нумеровать когда устанавливаешь биты. Такое часто используется в AVR микроконтроллерах. К примеру установить биты GICR |= (1 << INT0) | (1 << INT1); - разрешить прерывания INT0 и INT1. Если нумеровать с 1 то такое не получится.
Пример на массивах в C: Массив - последовательность однотипных данных в памяти, по сути это - указатель на память, где этот массив начинается, соответственно 0(первый) элемент находится на этом же месте, т.е его смещение равно 0 (адрес массива + 0). Для второго элемента смещение 1, для третьего 2 и тд. Но стоит учесть, что в записи "указатель + смещение" знак "+" задается арифметическим шагом, который равен размеру элемента в массиве в байтах. То есть, например, для int (4 байта) - запись "адрес + 1" будет значить "адрес + 4".
Это - наследие из чудесного единственно рассово верного языка Цэ, где конструкция array[1] - просто синтаксический сахар над указателями, типа *(array + 1), поэтому первый элемент массива оказывается нулевым. Забавно, что эта особенность позволяет в Цэ делать угарную для нубов вещь, типа 1[array] и получать тот же результат, поскольку от перестановки мест слагаемый сумма не меняется. Добро пожаловать в удивительный мир старых языков программирования и их культурного наследия в новых языках программирования... --- Сообщение объединено, May 12, 2023 --- И еще есть же Lua и еще несколько языков, где нумерация массивов происходит с единицы, но привыкать к этому, наверное, не стоит, если не хочешь всю жизнь писать на одном языке.
Конкретно это - это наследие языка B, предшественника C. В нём не было по сути типов данных кроме слов. И понять чем слово является - переменной или указателем можно было только из контекста применения - по окружающим символам. Поэтому 1[var] и var[1] в B транслировались в одно и то же - сложение двух слов с получением l-value по полученному адресу. Скорее всего он с таким же успехом переварил бы и 2[1]. И скорее всего поэтому в Си есть два разных оператора - operator. и operator-> - потому что опять таки в B видимо нужна была разница в операторах чтобы понять чем слово слева является - указателем на первое слово структуры или l-value экземпляром первого слова в структуре. Как то так. Причём я когда то давно находил, что структуры в самых даже первых не вышедших далеко из лаборатории версиях Си видимо по аналогии с B реализовались тем, что их поля были глобальными идентификаторами с численными значениями-смещениями, поэтому там прям как в ассемблере надо было делать типа point.Point2ВX, типа такого. Но это прям слабо известно, т.к. не дожило даже до первого бестселлера Кернигана и Ритчи.
а в чем отличие? по сути поля это и есть смещение от базы, только именованное. а оператор -> лишь сахар для *(pointer).field
С/С++ это довольно низкоуровневый язык(да, масло масленое, вода мокрая) Просто надо разбивать команды на микрокоманды, на самые элементарные микрокоманды. mov eax, [ebx+666h] shM:=ebx+666h ; локальный аппаратный регистр eax:=[shM] ;на самом деле тут куча микрокоманд, зависит от сложности процессора. 666h это смещения какого-та параметра в структуре или классе, что одно и тоже, и 0 это тоже смещения, может на виртуальную таблицу методов класса. Так что с нуля это естественно, по другому просто не может быть, на оборот с единицы это не правильно. Так же нумерация бит работает.
Нумерация с 1 прижилась в типах типа ShortString, где первый элемент (с 0 индексом) описывал длину строки, а строка начиналась с 1 индекса. Еще можно вспомнить про функцию ah=10/int 33, для которой в dx задается буфер начинающийся с длины самого буфера и в первом байте возвращается длина строки.
Ну и еще пример со структурами, там все точно также как и в массивах, указатель на структуру - указатель на первый элемент структуры. Code (Text): typedef struct Person { int age; int h; int w; } Person; int main() { void* offset = (&((Person*)0)->h); printf("%x", offset); return 0; }
Начинаю к этому немного привыкать Code (ASM): format PE64 console include 'win64a.inc' section '.text' readable executable mov rax,mass xor rcx,rcx poll: mov byte [rax],0xD3 ;заполняем нулевой элемент inc rcx ;а потом регистр rcx увеличиваем на 1 inc rax cmp rcx,255 ;256 элементов je mrq jmp poll mrq: sub rsp,8 invoke MessageBoxA,0,addr message,addr caption,0 invoke ExitProcess,0 section '.data' readable writeable mass db 256 dup(0) caption db 'JUMP',0 message db 'COMPARE',0 section '.idata' import data readable writeable library kernel32,'kernel32.dll',\ user32,'user32.dll' include 'api\kernel32.inc' include 'api\user32.inc'
Entropy, Code (ASM): xor eax,eax poll: mov mass[rax],0xD3 ;заполняем нулевой элемент inc eax or ah,ah ;256 элементов je poll
Конечно же rmn, но Code (ASM): Mov eDi, offset [mass] ; в 32-х короче "lea edi, mass" как в 64-х ? Mov Al, 0d3h Mov eCx, 256 ClD ; в 32-х не всегда по умолчанию вперед (как в 64-х не знаю). rep StosB А может процессор умный по скорости? А по памяти меньше кода.
R81..., Ну, можно написать Code (ASM): lea rdi, mass mov al, 0d3h mov rcx, 256 rep stosb если прям так памяти не хватает На глаз тут байт 18 lea и mov должны быть одного размера: там опкод, modrm и смещение. --- Сообщение объединено, Jun 1, 2023 --- всегда (если ты, конечно, сам перед этим этот флаг не трогал).
Для mov может не уместиться в 7-байтовый опкод. Зависит от базового адреса. И тогда mov будет 9 байтовый. Тогда как lea для 64-бит будет 7 байтовый всегда т.к. можно вычислять адреса относительно rip --- Сообщение объединено, Jun 2, 2023 --- В 64-битах также есть флаг DF