Явное назначение адресов для указателей C - PullRequest
0 голосов
/ 11 октября 2011
$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=0x7fffffffe2bc;
    y=0x7fffffffe3bc;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

Создает ошибку сегментации во время выполнения ( Нет предупреждений / ошибок времени компиляции) РЕДАКТИРОВАТЬ : (Предупреждения: Спасибо @KeithThompson)

x.c: в функции «main»:
x.c: 6: предупреждение: присваивание делает указатель из целого числа без приведения

[ 8626.812415] x[3198]: segfault at 7fffffffe2bc ip 000000000040054c sp 00007fff66a1dd70 error 6 in x[400000+1000]

Но когда я назначаю x, y q, w как это

$ cat x.c 
#include<stdio.h>
void main()
{
    int *x,q;
    int *y,w;
    x=&q;
    y=&w;
    *x=3;*y=4;
    printf("%d",(*x)/(*y));
}

и получаю вывод, который я получаю 0. Я даже проверил адреса q и w из gdb, я получил 0x7fffffffe2bc для q

Почему я не могу заставить указатель указывать в определенном месте и предоставить ему значение для хранения?

EDIT Адрес 0x7fffffffe2bc не является нераспределенным . Это адрес q из gdb

Breakpoint 1, main () at x.c:10
10      *x=3;*y=4;
(gdb) p q
$1 = 0
(gdb) p &q
$2 = (int *) 0x7fffffffe2bc
(gdb) 

Я понимаю, что такой способ написания кода плох, если не неправильн. Я просто написал это, чтобы увидеть, работает ли явное присвоение адресов или нет. Я бы никогда не тратил свое время на явное назначение адресов. Делать что-то подобное на самом деле звучит очень отсталым:)

$ gdb -q ./a.out 
Reading symbols from /home/eknath/needed2/a.out...done.
(gdb) r
Starting program: /home/eknath/needed2/a.out 
0

Program exited normally.
(gdb) q

Ответы [ 5 ]

3 голосов
/ 11 октября 2011

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

Если вы хотите динамически распределять переменные (т.е. под своим собственным контролем), используйте malloc:

int *x = (int*) malloc( sizeof(int) );
*x = 2;

// when done, free the memory
free( (void*) x );
1 голос
/ 11 октября 2011

Этот код:

int *x,q;
...
x=0x7fffffffe2bc;

недействителен.Это нарушение ограничения, означающее, что любой соответствующий компилятор должен выдавать диагностическое сообщение.Вы сказали «При компиляции этой программы нет предупреждений / ошибок», что означает, что либо вы используете старый компилятор, либо вы используете новый компилятор неправильно.

x имеет тип int*;0x7fffffffe2bc имеет некоторый целочисленный тип.Не существует неявного преобразования целочисленного типа в int* (за исключением специального случая 0, константы нулевого указателя).

Вы можете легально написать что-то вроде:

x = (int*)0x7fffffffe2bc;

но это очень плохая идея.Это делает вашу программу чрезвычайно непереносимой.Это может (или не может) произойти с вашей конкретной системой.

Что бы вы ни пытались сделать, это не способ сделать это.У вас нет возможности узнать, что 0x7fffffffe2bc (при преобразовании в int*) является действительным адресом - и даже если это действительный адрес, этого не произойдет, если вы запустите программу даже в немного другой среде.

РЕДАКТИРОВАТЬ :

Я попытался воспроизвести вашу программу в моей системе (где адреса совершенно разные), напечатав адреса q и w, а затемвстраивание адресов в код.Фактический адрес меняется каждый раз, когда я запускаю программу, даже когда я не изменяю и не перекомпилирую саму программу.Я думаю, что некоторые системы делают это намеренно, как средство защиты.(Я вижу, что в ответе dmckee это уже упоминалось.)

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

Если вам нужен адрес q, способ получитьэто &q.

0 голосов
/ 20 апреля 2016
void myFunction(char *addr)
{
#ifdef UMEM_DEBUG
    if (addr == (char *) 0xdeadbeefdeadbeef)
    {
        return;
    }
#endif
...
}

Это работает и является хорошим примером того, когда вы действительно хотите это сделать. Просто получите правильный тип на основе типа addr

0 голосов
/ 11 октября 2011

Проблема не в коде и не в компиляторе / компоновщике. Обе программы работают так, как вы ожидаете. Просто есть одна большая НО : то, что вы можете указывать на память, это не значит, что вам будет разрешено обращаться к ней через MMU (скажем, в операционной системе).

Позвольте мне уточнить это: обычно вы можете получить доступ только к памяти, которой вы «владеете» (стек / куча). В обоих случаях присваивания x и y действительны. Сложнее всего, когда вы получаете доступ к памяти (чтение или запись). В первом случае вы присваиваете какое-то случайное значение указателю, поэтому нет значительной вероятности, что это местоположение будет в области действия программы (== не может коснуться этого). Хотя во втором случае вы обращаетесь к ячейке памяти переменной, которой вы могли бы владеть.

Почему может? Потому что при оптимизации по переменным q и w будут оптимизированы, потому что они никогда не используются.

Помните: никогда не ссылайтесь на неинициализированную переменную , если вам не нравятся проблемы

0 голосов
/ 11 октября 2011

Подобные вещи полностью зависят от реализации / среды (и в общем случае неопределенного поведения), но имеют место во встроенных системах и других средах, где у вас нет уровня ОС между вами и абсолютно всем.

Многие операционные системы с полным набором услуг рандомизируют начальный адрес стека и / или кучи, чтобы усложнить некоторые атаки, и в этом случае вы не сможете выполнять какие-либо надежные трюки.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...