[英]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
表示用於比特pageNumber
和F
為比特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.