簡體   English   中英

C 中的 memset 和 (&, >>) 符號

[英]memset and (&, >>) symbols in C

我發現了一個我無法理解一段代碼的項目。 虛擬內存

#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 是 logicalAddress 和 pageNuberMask 存儲在一起的值。 而這個字符 & 加入他們。 然后我們在 8(>> 8) 上做偏移。

以及為什么使用 memset 很危險。

出於性能和內存原因, page中的pageNumber和偏移量存儲在單個unsigned值中。

我將在注釋中使用帶有0b前綴的c++14位表示來解釋。

unsigned logicalAddress = someValue;           // <- 0bPPPPPPPPFFFFFFFF

其中P表示用於比特pageNumberF為比特offsetNumber ;

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

關於memset如果使用得當,使用它是沒有危險的。

(出於說明目的,此答案假定地址為 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); .
  • 預處理器宏是為各種參數定義的,例如PAGE_SIZE為 256 ,但部分代碼會忽略這些並使用硬編碼常量,如Frame*256 + Index 這是錯誤的秘訣。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM