Как работает int * ptr = 5; отличается от int * ptr = адрес переменной? - PullRequest
3 голосов
/ 19 марта 2020

Хотя это очень просто c и может показаться глупым, я пытаюсь понять, в чем разница между int *ptr = 45 или 0xc8750; (некоторым числом) против int *ptr= &a; (адрес переменной) .

То, что я уже знаю:

  • Указатели предназначены для хранения адресов переменных и для изменения содержимого точечные переменные (но я хочу знать, как это будет достигнуто)
  • В последнем случае я могу присвоить *ptr другому законному адресу.
  • Но в первом случае это Недопустимо!.

Почему последнее недопустимо, если оба адреса / числа являются целыми числами? Как по-разному они будут обрабатываться при хранении в памяти?

У меня есть два кода / программы, в основном, чтобы выделить одно и то же:

case-1:

#include <stdio.h>

int main()
{    
    int *ptr = 0xc42; // is this stored in read only memory?!! which later leads to seg faults in further assignments?!
    *ptr = 45; //illegal leads seg fault.
    return 0;
}

case-2:

int main()
{
    int a=10, b=20;
    int *ptr = &a;  // is here get any special treatment and object will be created for *ptr!!!
    *ptr = &b; //legal
    printf(" *ptr = %d \n", *ptr);
    *ptr = 20; //legal !!
    printf(" *ptr = %d \n", *ptr);
    *ptr = 50; //legal
    printf(" *ptr = %d \n", *ptr);
    return 0;
}

Как мы видим, *ptr = 20 и *ptr = 50 являются законными и штрафными! (Нет ошибок сегментации).

Почему это назначение int *ptr = 0xc989 или 5 отличается от int *ptr = &variable?.

Ответы [ 3 ]

3 голосов
/ 19 марта 2020

Прежде всего int *ptr = 0xc42; недопустимо C и не будет корректно компилироваться на компиляторе, настроенном на строгий стандарт C. С g cc, clang и i cc это означает компиляцию с -std=c11 -pedantic-errors. Подробнее см. «Указатель из целого числа / целое число из указателя без приведения»: .

int *ptr = (int*)0xc42; действительно C, но подозрительно. Для пояснения, это хранит адрес внутри самой переменной-указателя , не хранит значения. Поэтому, если вы знаете , что по адресу 0xc42 имеется элемент размером int, например, аппаратный регистр с отображением в памяти, вы можете напрямую указать это. Но при этом это будет иметь смысл только при использовании volatile: volatile int *ptr = (volatile int*)0xc42;. Подобный код в основном имеет смысл во встроенных системах и другом аппаратном программировании.

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

3 голосов
/ 19 марта 2020

Начнем с основ: указатель - это переменная, содержащая адрес, указывающий на данные данного типа. Если мы объявим, что

datatype* foo;

foo (который в настоящее время не инициализирован) будет содержать адрес переменной типа datatype, а , относящийся к it

*foo = ...;

мы получаем доступ к этому адресу и сохраняем его значение.


В обоих случаях у нас есть * foo, но они не совпадают!

  • В В первом случае звездочка относится к datatype. Тип переменной datatype *; имя переменной foo. foo содержит адрес.
  • Во втором случае мы разыменовываем адрес, чтобы получить к нему доступ. Звездочка относится к переменной для выполнения разыменования указателя.

Итак, когда вы пишете

int *ptr = 0xc42; // is this stored in read only memory?!!
                  // which later leads to seg faults in further assignments?!
*ptr = 45; //illegal leads seg fault.
  • с int *ptr = 0xc42;, вы говорите компилятору, который вы объявляете переменную с именем ptr, типа int * и первое значение которой 0xC42. ( Примечание: , как правильно указано пользователем Лундин , это назначение требует дальнейшего приведения, чтобы быть действительным C) .
  • С помощью *ptr = 45; вы получаете доступ к адресу, указанному ptr, и присваиваете значение 45. Это законно? Хорошо, это если вы ранее присвоили действительный адрес (и вообще говоря, это если вы назначаете указателю адрес другой переменной с помощью оператора &, например, int *ptr = &a;). Но если вы назначите ему случайное целое число ... это, вероятно, приведет к ошибке сегментации.
2 голосов
/ 19 марта 2020

Логически, если вы уверены, что местоположение, 0xc989, сохраняет то, что вам нужно, int *ptr = 0xc989 совершенно правильно (с точки зрения вашей концепции мышления, как сказал Роберто Кабони).

Технически, как сказал Лундин, вам нужно разыграть его в соответствии со C стандартами.

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