1

Тема: Вивід адреси

Взявся на свою голову вчити сі. Все наче виходить, але не дається мені одна цікава задача поки що. Є завдання вивести адресу змінної, зміст в шіснадцядковому вигляді і просто зміст функцією write. Зміст в шіснадцятковому вигляді і просто зміст можу вивести без проблем а от саму адресу не виходить. Я так розумію що треба записати значення адреси в змінну unsigned long int алеж стикаюсь з тим що значення виходить за рамки цього типу. От власне хотів би почути пораду або приклад як це можна зрозуміть та виконать

2

Re: Вивід адреси

Цілий тип, у який гарантовано влазить адреса, зветься size_t (визначено у <stddef.h>, але використовується в інших бібліотеках також). Використовується для визначення розміру об'єктів у пам'яті. Специфікатор розміру для форматованого виводу size_t - z (%zu чи %zx).
size_t беззнаковий, але має знаковий аналог - ptrdiff_t, який використовується, як можна здогадатися, для обчислення різниці між адресами.

Подякували: leofun01, Potaskun2

3

Re: Вивід адреси

Перепрошую, зачитався вашим рішенням і не написав правильного.
Для виведення покажчиків є окремий специфікатор - %p. Не треба нікуди його перетворювати.

Подякували: leofun01, Potaskun2

4

Re: Вивід адреси

Секрет полягає в тому що мені потрібно написати функцію тільки використовуючи функцію write і не використовуючі інші бібліотеки хоча може і помиляюсь... А без використання типу size_t Це можливо зробити?

5

Re: Вивід адреси

А без використання типу size_t Це можливо зробити?

Звісно. Ідея size_t в тому, що розмір покажчика залежить від архітектури; на 32-бітних системах це 4 байти, на 64-бітних - 8 байтів. Вам, швидше за все, потрібен unsigned long long int, і саме так для вашої архітектури size_t і визначений.

Подякували: Potaskun1

6

Re: Вивід адреси

koala написав:

Цілий тип, у який гарантовано влазить адреса, зветься size_t (визначено у <stddef.h>, але використовується в інших бібліотеках також). Використовується для визначення розміру об'єктів у пам'яті. Специфікатор розміру для форматованого виводу size_t - z (%zu чи %zx).
size_t беззнаковий, але має знаковий аналог - ptrdiff_t, який використовується, як можна здогадатися, для обчислення різниці між адресами.

Цілі типи, у які гарантовано влазить адреса, звуться uintptr_t/intptr_t.
А в size_t гарантовано влазить розмір об'єкта (значення саме цього типу повертає sizeof()).
Про те, що це різні речі, може розповісти compact модель пам'яті для i80x86 у 16-бітному режимі ядра, коли розмір об'єкта не може бути більшим за (64К-1) і для size_t досить 16 біт, а вказівники 32-бітні (seg:offs) і для void* та відповідно uintptr_t треба 32 біти.
Подібна штука може бути для 80386+ у 32-бітному режимі (сегментація працює) при не пласкій моделі, і size_t 32-бітний але адреса потребує пари 32-бітних значень seg:offs

p.s. А ще є ssize_t, для якого гарантовано що він може зберігати щонайменше одне від'ємне число — -1

Подякували: leofun01, koala, Potaskun3

7

Re: Вивід адреси

void print_addr(unsigned long long int addr, int i){
    char a[] = "0123456789abcdef";

    if(addr > 16){
        print_addr(addr / 16, i + 1);
    }

    if(addr < 16){
        while(i != 15){
            putchar('0');
            i++;
        }
    }

    putchar(a[addr % 16]);
}

Ось так вийшло
Алеж то тільки початок программи

8

Re: Вивід адреси

Використовуйте тег code

Якщо функція повинна друкувати значення вказівника, то краще щоб її аргумент мав тип void*, а всі приведення до цілих чисел робилися всередині.
Тобто краще зробити щось таке

/* може знадобитися ще десь */
void print_hex(unsigned long long value)
{
    /* ... */
}

void print_addr(void *addr)
{
    print_hex((unsigned long long int)addr);
}

Рекурсія тут не надто потрібна штука, і якщо без неї можна обійтися — краще обійтися.
Можна друкувати у локальний масив, який спочатку заповнювати ззаду починаючи з останньої цифри, а тоді його вивести через write().
І зваовнювати тоді можна без ділення

    /* Тіло циклу, індекс i біжить від максимального значення до 0
       Початкові нулі вийдуть автоматично
    */
    str[i] = "0123456789abcdef"[value & 0x0F];
    value >>= 4;
Подякували: leofun01, Potaskun2

9

Re: Вивід адреси

void print_str(char *str){
int i;

i = 0;
while(str[i]){
if(str[i] < 32 || str[i] > 127){
1putchar('.');
i++;
}
else{
1putchar(str[i]);
i++;
}
}
write(1, "\n", 1);
}


void print_hex(char *in, int len){

int i;
int j;
char a[] = "0123456789abcdef";

i = 0;
j - 0;

while(i != len){
if(j / 2){
j = 0;
write(1, " ", 1);

}
        1putchar(a[in[i] / 16]);
        1putchar(a[in[i] % 16]);
        i++;
        j++;
}
write(1, " ", 1);
}

void print_addr(unsigned long long int addr, int i){

char a[] = "0123456789abcdef";


if(addr > 16){
        print_addr(addr / 16, i + 1);
}
if(addr < 16){
        while(i != 15){
                1putchar('0');
                i++;
        }
}
1putchar(a[addr % 16]);
}


void print_memory(void *addr, unsigned int size){


unsigned long long int a;

a = (unsigned long long int)&addr;


print_addr(a, 0);
write(1, ": ", 2);
print_hex(addr, 1strlen(addr));
print_str(addr);
}

Отака бідолага вийшла. З приводу рекурсії натяк зрозумів. Поки так як на стадії навчання, буду припускатись помилок бо дивлячись на старі помилки потроху приходить розуміння. До речі поки писав цю, помітив помилку в іншій программі:)

10

Re: Вивід адреси

А як вичіслить кінець воід чи то мрії?

11

Re: Вивід адреси

Potaskun написав:

А як вичіслить кінець воід чи то мрії?

Я не зрозумів запитання.

12

Re: Вивід адреси

Potaskun написав:

А як вичіслить кінець воід чи то мрії?

Ви б для початку українську мову вивчили, а потім уже на C переходили...