memset и (&, >>) символы в C - PullRequest
       11

memset и (&, >>) символы в C

0 голосов
/ 22 февраля 2020

Я нашел один проект, в котором я не могу понять один фрагмент кода. Виртуальная память

#include <assert.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#define TLB_SIZE 16
#define PAGE_SIZE 256
#define FRAME_SIZE 256
#define PHYSICAL_MEMORY_SIZE PAGE_SIZE *FRAME_SIZE

int logicalAddress = 0;
int offsetNumber = 0;
int pageNumber = 0;
int physicalAddress = 0;
int Frame = 0;
int Value = 0;
int Hit = 0;
int tlbIndex = 0;
int tlbSize = 0;

unsigned pageNumberMask = 65280;  // 1111111100000000
unsigned offsetMask = 255;        // 11111111

int tlbHitCount = 0;
float tlbHitRate = 0;
int addressCount = 0;
int pageFaultCount = 0;
float pageFaultRate = 0;

struct tlbTable {
  unsigned int pageNum;
  unsigned int frameNum;
};

int main(int argc, char *argv[]) {
  // Check to see if user inputs addresses.txt
  if (argc != 2) {
    fprintf(stderr, "Usage ./VirtualMem_Manager <Filename.txt> \n");
    exit(1);
  }
  // Open addresses.txt, BACKING_STORE.bin, and
  // Create Output.txt to store program results
  FILE *addresses = fopen(argv[1], "r");
  FILE *BACKINGSTORE = fopen("BACKING_STORE.bin", "rb");
  FILE *Output = fopen("addressOutput.txt", "w");

  int physicalMemory[PHYSICAL_MEMORY_SIZE];
  char Buffer[256];
  int Index;

  // Declare and initialize pageTable[] array to -1
  int pageTable[PAGE_SIZE];
  memset(pageTable, -1, 256 * sizeof(int));

  // Declare and initialize tlb[] structure to -1
  struct tlbTable tlb[TLB_SIZE];
  memset(pageTable, -1, 16 * sizeof(char));

  // Read each address from addresses.txt
  while (fscanf(addresses, "%d", &logicalAddress) == 1) {
    addressCount++;

    // set the page number and offset for each logical address
    pageNumber = logicalAddress & pageNumberMask;
    pageNumber = pageNumber >> 8;
    offsetNumber = logicalAddress & offsetMask;
    Hit = -1;

    // Check to see if the page number is already in the tlb
    // If it is in tlb, then it is tlb hit
    for (Index = 0; Index < tlbSize; Index++) {
      if (tlb[Index].pageNum == pageNumber) {
        Hit = tlb[Index].frameNum;
        physicalAddress = Hit * 256 + offsetNumber;
      }
    }

    if (!(Hit == -1)) {
      tlbHitCount++;
    }
    // This "else if" loop is the tlb miss
    // Gets the physical page number from page table
    else if (pageTable[pageNumber] == -1) {
      fseek(BACKINGSTORE, pageNumber * 256, SEEK_SET);
      fread(Buffer, sizeof(char), 256, BACKINGSTORE);
      pageTable[pageNumber] = Frame;

      for (Index = 0; Index < 256; Index++) {
        physicalMemory[Frame * 256 + Index] = Buffer[Index];
      }
      pageFaultCount++;
      Frame++;

      // FIFO algorithm for the tlb
      if (tlbSize == 16) tlbSize--;

      for (tlbIndex = tlbSize; tlbIndex > 0; tlbIndex--) {
        tlb[tlbIndex].pageNum = tlb[tlbIndex - 1].pageNum;
        tlb[tlbIndex].frameNum = tlb[tlbIndex - 1].frameNum;
      }

      if (tlbSize <= 15) tlbSize++;

      tlb[0].pageNum = pageNumber;
      tlb[0].frameNum = pageTable[pageNumber];
      physicalAddress = pageTable[pageNumber] * 256 + offsetNumber;
    } else {
      physicalAddress = pageTable[pageNumber] * 256 + offsetNumber;
    }

    // Gets the value from the bin file provided
    Value = physicalMemory[physicalAddress];
    // print the addresses and value to Output.txt
    fprintf(Output, "Virtual Address: %d Physical Address: %d Value: %d \n",
            logicalAddress, physicalAddress, Value);
  }

  // The statistics of the program
  pageFaultRate = pageFaultCount * 1.0f / addressCount;
  tlbHitRate = tlbHitCount * 1.0f / addressCount;

  // Close files provided for the project
  fclose(addresses);
  fclose(BACKINGSTORE);

  // Print the statistics of the program to Output.txt
  fprintf(Output, "Number of Addresses: %d\n", addressCount);
  fprintf(Output, "Number of Page Faults: %d\n", pageFaultCount);
  fprintf(Output, "Page Fault Rate: %f\n", pageFaultRate);
  fprintf(Output, "TLB Hits: %d\n", tlbHitCount);
  fprintf(Output, "TLB Hit Rate %f\n", tlbHitRate);

  // Close Output.txt
  fclose(Output);

  return 0;
}

Я не могу понять эти три строки.

pageNumber = logicalAddress & pageNumberMask;
pageNumber = pageNumber >> 8;
offsetNumber = logicalAddress & offsetMask;

Как я понимаю, papeNumber - это значение, где логический адрес и pageNuberMask хранятся вместе. И этот чар & присоединиться к ним. Затем мы делаем смещение на 8 (>> 8).

И почему использование memset опасно.

Ответы [ 2 ]

0 голосов
/ 22 февраля 2020

(В целях иллюстрации этот ответ предполагает, что адреса являются 32-битными, что, по-видимому, соответствует коду в вопросе.)

pageNumber = logicalAddress & pageNumberMask;
pageNumber = pageNumber >> 8;
offsetNumber = logicalAddress & offsetMask;

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

pageNumberMask - это значение, которое было подготовлено для имеют 1 в битах номера страницы и 0 в других местах. Затем операция logicalAddress & pageNumberMask выполняет побитовое И, которое выдает значение, в котором установлены только те биты, которые были установлены в битах номера страницы logicalAddress. Другими словами, он создает значение, при котором верхние биты и биты смещения очищаются, эффективно изолируя биты номера страницы.

Затем pageNumber >> 8 сдвигает эти биты номера страницы до младших битов, поэтому Результатом является номер страницы. Этот номер страницы можно затем использовать для индексации массивов.

Аналогично, offsetMask - это подготовленное значение с 1 с в битах смещения и 0 с в другом месте, а logicalAddress & offsetMask извлекает только биты смещения.

Обратите внимание, что logicalAddress & pageNumberMask служит цели, только если могут быть установлены биты над битами номера страницы. Это связано с тем, что pageNumber >> 8 все равно удаляет младшие биты, поэтому нет смысла очищать их с помощью операции &. Таким образом, этот код отделяет биты номера страницы от старших бит, но не использует эти старшие биты. Это может быть связано с тем, что это упрощенный пример обучения, а в реальном коде для развертывания используются верхние биты.

И почему использование memset опасно.

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

Дефекты в коде

Код в вопросе имеет ряд недостатков, поэтому он не является хорошим примером для обучения:

  • struct tlbTable tlb[TLB_SIZE];, за которым следует memset(pageTable, -1, 16*sizeof(char));, выглядит как ошибка. pageTable был инициализирован ранее, и это, вероятно, предназначалось для инициализации tlb. И размер неправильный; tlb имеет 16 элементов (TLB_SIZE равно 16), каждый из которых состоит из нескольких байтов. Эта строка, вероятно, должна быть memset(tlb, -1, sizeof tlb);, а предыдущая memset должна быть memset(pageTable, -1, sizeof pageTable);.
  • Макросы препроцессора определены для различных параметров, таких как 256 для PAGE_SIZE, но затем части кода игнорируются они и используют жестко закодированные константы, как в Frame*256 + Index. Это рецепт для ошибок.
0 голосов
/ 22 февраля 2020

По соображениям производительности и памяти pageNumber и смещение в page хранятся в одном unsigned значении.

Я буду использовать c++14 представление битов с префиксом 0b в комментариях, чтобы объяснить .

unsigned logicalAddress = someValue;           // <- 0bPPPPPPPPFFFFFFFF

, где P обозначает биты для pageNumber и F биты для offsetNumber;

pageNumber = logicalAddress & pageNumberMask;  // <- 0bPPPPPPPP00000000
pageNumber = pageNumber >> 8;                  // <-         0bPPPPPPPP
offsetNumber = logicalAddress & offsetMask;    // <-         0bFFFFFFFF

Об использовании memset использование не опасно, если используется правильно.

...