Подтвердить что ты не робот

Почему эта функция передает int-аргумент во volatile pointer и сразу же разыгрывает его?

Я просто хочу знать, что делает функция ниже

static int myfunc(int val)
{
    return *(volatile int *)val;
}
4b9b3361

Ответ 1

Если val является указателем, когда вы передаете его этой функции, он гарантирует, что значение, указанное этим указателем, будет считано и возвращено вызывающему.

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

Маркировка здесь указатель как volatile заставит компилятор не оптимизировать чтение, если он обнаруживает, что значение не используется.

Пример:

#define FIFO_ADDRESS 0x800050

static int myfunc(int val)
{
    return *(volatile int *)val; // the address *will* be read
}

static int bad( int val )
{
    return *(int*)val; // might be optimized to nop()  
                       // by the compiler if the value 
                       // is not used by the caller
}

int main(){
   bad( FIFO_ADDRESS );    // could be NOP since return value is not used

   myfunc( FIFO_ADDRESS ); // *WILL* perform a READ operation on the FIFO, 
                           // even though the result is not used, because 
                           // of the volatile keyword

}

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

#define FORCE_INT_PTR_READ( address ) *(volatile int *)address 

Не могли бы вы привести пример использования в вашем случае?

Ответ 2

Кажется, он пытается запутать оптимизатора (и, возможно, пользователя). Он принимает целое число, рассматривая его как указатель на целое число и разыгрывая его. "Volatile" гарантирует, что оптимизатор будет генерировать код для этого разыменования в этой точке и не позволит оптимизатору опустить выборку из памяти. Обычно это используется для доступа к зарегистрированным аппаратным регистрам памяти,

Ответ 3

Он выполняет следующие действия:

  • Пропускает целое число со знаком к функции.
  • Преобразует содержимое знакового целого в указатель. Это не имеет смысла, поскольку указатели не могут быть подписаны. Формально это тоже неточно определенное поведение, и все может случиться.
  • Ключевое слово volatile предполагает, что содержимое val должно совпадать с физическим аппаратным адресом. При чтении с таких адресов ключевое слово volatile необходимо, так как содержимое регистра аппаратного обеспечения может измениться в любое время.
  • Он принимает содержимое этого адреса и обрабатывает его как int, который затем возвращается.
  • static означает, что функция имеет локальную область действия.

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

В целом, это плохо написанный код, который не является ни безопасным, ни четким, ни портативным. Вы не получите никаких ценных знаний, глядя на него.

Ответ 4

Он передает val указателю и возвращает его значение. Звонки на myfunc() будут работать, только если ваш вид   int i, j;

i = 10;
j = myfunc( (int)&i )` 

Это должно установить j на 10

НО он не будет работать на 64-битных системах, где sizeof(int *) равно 8 и, следовательно, больше, чем sizeof(int) или на некоторых старых системах с sizeof(int) == 2