Адрес памяти для каждого байта отдельный?

У каждого байта есть свой адрес?

Если создать переменную int (у меня весит 4 байта). Адрес памяти один для 4 байт, или для каждого байта отдельный адрес?

int x = 1; 

например переменная x весит 4 байта, я могу как-то обращаться к каждому байту отдельно?

в памяти это выглядит так?

            0xFF // address
00000000000000000000000000000001 // 32bit

или так?

  0x1 
00000000 // 8bit
  0x2
00000000
  0x3
00000000
  0x4
00000001 

Ответы (3 шт):

Автор решения: Harry

В памяти для 32-битного int это выглядит так:

0x1233  0x1232  0x1231  0x1230
00000000000000000000000000000001

если это little-endian, а если big-endian, то

0x1230  0x1231  0x1232  0x1233
00000000000000000000000000000001

Т.е. это единое целое из 4 байтов, но в принципе вы можете обратиться (адресовать) к каждому байту отдельно. Но единое число типа int занимает 4 байта и имеет адрес (в приведенном случае) 0x1230.

Грубо говоря, вы можете обратиться к каждому ученику в классе (но не отдельно к его, скажем, желудку :)), но для какого-то школьного мероприятия класс — единое целое со старостой класса во главе, по которому можно адресовать весь класс :)

→ Ссылка
Автор решения: VladD

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

Мой любимый пример: вот такой код

unsigned int sum(unsigned int num)
{
    unsigned int acc = 0; 
    for (unsigned int i = 0; i <= num; i++)
        acc += i;
    return acc;
}

оптимизирующий компилятор преобразует в такой ассемблер:

sum(unsigned int):
        mov     ecx, edi
        lea     eax, [rdi - 1]
        imul    rax, rcx
        shr     rax
        add     eax, edi
        ret

(который можно примерно перевести назад на C++ как return num * (num - 1) / 2 + num).

Сколько байт весит переменная i исходного кода? Вопрос некорректен.


Ещё один любопытный пример: код

class adder
{
    int a, b;
public:
    adder(int a, int b) : a(a), b(b) {}
    int get() { return a + b; }
};

int add0(int x, int y)
{
    return x + y;
}

int add1(int x, int y)
{
    adder w(x, y);
    return w.get();
}

int add2(int x, int y)
{
    adder* pw = new adder(x, y);
    int result = pw->get();
    delete pw;
    return result;
}

int add3(int x, int y)
{
    adder* pw = new adder(x, y);
    try
    {
        int result = pw->get();
        delete pw;
        return result;
    }
    catch (...)
    {
        delete pw;
        throw;
    }
}

int add4(int x, int y)
{
    std::unique_ptr<adder> pw { new adder(x, y) };
    return pw->get();
}

скомпилровался в обычное

add0(int, int):
        lea     eax, [rdi + rsi]
        ret
add1(int, int):
        lea     eax, [rdi + rsi]
        ret
add2(int, int):
        lea     eax, [rdi + rsi]
        ret
add3(int, int):
        lea     eax, [rdi + rsi]
        ret
add4(int, int):
        lea     eax, [rdi + rsi]
        ret

то есть все пять функций компилируются в аналог return x + y;. Какой адрес объекта adder? Где он расположен, в стеке или в куче? Вопрос некорректен.

Компилятор обязан следовать семантике вашего кода: если код по сути считает сумму чисел, то после компиляции должна получиться сумма чисел. Компилятор не обязан следовать синтаксису вашего кода: если для сложения вы используете дополнительный класс, компилятор вовсе не обязан делать то же самое. Поэтому компилятор имеет право под капотом менять код, убирать и добавлять переменные, менять алгоритм с квадратичного на линейный и наоборот, убирать аллокации, всё что угодно. Понятия исходного кода (переменные, функции, классы, команды) вовсе не обязаны иметь соответствие в компиляте.

→ Ссылка
Автор решения: eri

Не пойму почему в ответах нет прямого ответа на вопрос: как разбить int на байты?

#include <stdio.h>

int main () {
   int i = 1;
   unsigned char *b = (unsigned char*) &i;
   
   printf("%X %X %X %X\n", b[0], b[1], b[2], b[3]);

   return(0);
}

Один из вариантов.

→ Ссылка