2016-05-19 3 views
0

Если предположить, что адрес 0xCF800000 свободен для записи:Указатель на конкретный адрес в C

А) Правильно ли сказать, что оба кода дают одинаковый результат?

int main(void) 
{ 
    volatile unsigned long *pt = (volatile unsigned long *) 0xCF800000; 
    *pt = 0x00000000; 
} 

и

int main(void) 
{ 
    (*(volatile unsigned long *) 0xCF800000) = 0x00000000; 
} 

B) На первом коде, оператор "(летучий беззнаковое долго *)" перед 0xCF800000 необходимо или избыточность?

C) В первом коде есть переменная pt, у которой есть свой собственный адрес, где я помещаю некоторый контент: 0xCF800000. При разыменовании pt компьютер берет содержимое pt (0xCF800000), «находит» этот адрес и присваивает этому месту 0x00000000. Во втором коде я не могу точно понять, как это работает, поскольку нет переменной. Похож на информацию 0xCF800000 «нигде».

+1

Примечание: Я не думаю, что требуется «volatile». Объект в указанном адресе ссылается только один раз, поэтому его все равно нужно получить. – wildplasser

+1

Эти вопросы взяты из собеседования? – user31264

+0

ahahaha. Нет почему? @ wildplasser действительно! Неустойчивость существует только потому, что это сомнение появляется во время класса о GPIO –

ответ

0

вы сделали отливку (без знака long *), что означает, что компилятор обрабатывает это значение как указатель на unsigned long и не жалуется. Но, как сказал @ user3386109, всегда хорошо проверять себя.

0

Вы на самом деле отправил 3 вопроса, каждый из которых требует отдельного ответа, так:
что касается: (! Так)
В зависимости от значения, которое Вы пишете в этой ячейке памяти.

Вы находитесь в безопасности так долго, если это ноль или множество небольших значений. Но, если старший значащий бит этого значения равен 1, и, если по некоторым причинам он будет расширен по значению (в зависимости от других в вашем актерском составе, см. Мой ответ на ваш вопрос B) - тогда вы столкнетесь с проблемами ,
Чтобы избежать этих проблем, вы должны суффиктировать значение с помощью u, чтобы указать, что оно без знака (опять же, это неважно, если оно равно нулю).

Итак, если ваше постоянное значение для хранения будет, например, 0xA0000000 (обратите внимание, что самый старший бит - 1!), Вы должны написать его как: 0xA0000000u.

КСТАТИ: 0x00000000 только 0, вам не нужно писать, что много нулей в ней, но я понимаю, что это является частью более длинного кода, и вы хотите быть последовательны с вашим другом, больше значения

0

На самом деле вы отправили 3 вопроса, каждый из которых требует отдельного ответа, поэтому:
Относительно B:
Код: (volatile unsigned long *) - это отливка. Его необходимость зависит от размера целочисленного типа, используемого для хранения адресов в вашем компиляторе (этот тип должен быть typedef 'ed до size_t вашим компилятором). Вкратце:
Вы в порядке без литья здесь, если эта буквальная константа имеет столько битов, сколько адресов, используемых вашим компилятором, т. Е. Если ваш компилятор использует 32-разрядные адреса.
вам нужен актер, если ваш компилятор использует более 32 бит для адресов. Это играет свою роль, потому что вы разыскиваете эту литеральную константу как адрес (используя унарный оператор *). В этом случае помните, что литеральная константа, такая как 0xCF800000, будет расширена с ее текущих 32 бит.Поскольку старший бит 0xCF800000 является «1», поэтому это приведет к так называемому подписанному расширению (ведущий «1» будет скопирован на самые значащие бит), поэтому вы получите другой адрес памяти, чем тот, который вы хотеть !

Другой вопрос, если вам нужен volatile в вашем литье. Вам нужно только volatile в некоторых конкретных случаях, а именно, когда ячейка памяти может использоваться некоторым кодом другими устройствами в то же время. См. Why is volatile needed in C? .

0

Во втором коде я не могу точно понять, как это работает, поскольку нет переменной. Похож на информацию 0xCF800000 «нигде».

Чтобы ответить на ваши вопросы C): Это числовое число, которое позднее вызывается на указатель. В большинстве компьютерных систем литерал до тех пор, как (0xCF800000) будет скомпилирован в непосредственную, а разыменование значения указателя - это команда чтения памяти.

Давайте посмотрим на то, что ваш второй пример кода, скомпилированного в на x86:

.section __TEXT,__text,regular,pure_instructions 
    .macosx_version_min 10, 11 
    .globl _main 
    .align 4, 0x90 
_main:         ## @main 
    .cfi_startproc 
## BB#0: 
    pushq %rbp 
Ltmp0: 
    .cfi_def_cfa_offset 16 
Ltmp1: 
    .cfi_offset %rbp, -16 
    movq %rsp, %rbp 
Ltmp2: 
    .cfi_def_cfa_register %rbp 
    xorl %eax, %eax 
    movl $3481272320, %ecx  ## imm = 0xCF800000 
    movl %ecx, %edx 
    movq $0, (%rdx) 
    popq %rbp 
    retq 
    .cfi_endproc 

В частности, три линии

movl $3481272320, %ecx  ## imm = 0xCF800000 
    movl %ecx, %edx 
    movq $0, (%rdx) 

Считывает постоянное значение числа в регистр, а затем записать 0 в память, адрес которой совпадает с адресом этого регистра.

0

Вы на самом деле отправил 3 вопроса, каждый из которых требует отдельного ответа, так:
Что касается C:
Вы спрашиваете, как: (*(volatile unsigned long *) 0xCF800000) = 0x00000000; работает, но я уверен, что вы это знаете, вы просто не знаете, что вы знаете. ;-)
Указанная инструкция - это просто задание. Для того, чтобы выполнить работу, сначала необходимо оценить как ее левую сторону, так и ее правую сторону.
Огромное разнообразие правильных выражений в правой части. Левая сторона имеет множество ограничений, поскольку она должна оцениваться в памяти. Примером такой памяти является int a, поэтому вы можете написать: a = 0x00000000.
Другая ячейка памяти - int tab[N], поэтому вы можете написать: tab[0]= 0x00000000;
Еще один пример: int* p, поэтому вы можете написать: *p = 0x00000000.
Как вы видите, мы подошли очень близко к вашему вопросу: если вы согласны с тем, что *p, который расширяется до адреса памяти, может использоваться в левой части инструкции назначения, почему бы не постоять?
Константы вполне нормально здесь, так что вы можете написать очень просто:
*(int*)0 = 5
, что означает: принимать нулевое значение, то бросайте его (= лечить нравится) адрес с int*, затем разыменованиями этого адреса с унарный оператор *, затем присвойте целочисленное значение 5 этой ячейке памяти.
Конечно, мой последний пример предполагает, что ячейка памяти 0 доступна для записи.Кроме того, все мои два предыдущих ответа в этой теме, касающиеся расширений битов, должны применяться здесь, теперь я пропускаю литье только для ясности

Смежные вопросы