C 中的 memset 和 (&, >>) 符号
memset and (&, >>) symbols in C
我发现了一个项目,我无法理解一段代码。Virtual memory
#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 很危险。
出于性能和内存原因,pageNumber
和 page
中的偏移量存储在单个 unsigned
值中。
我会在评论中用c++14
位表示加上0b
前缀来说明。
unsigned logicalAddress = someValue; // <- 0bPPPPPPPPFFFFFFFF
其中 P
表示 pageNumber
的位和 offsetNumber
的 F
位;
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
无论如何都会删除低位,因此使用 &
操作清除它们是没有意义的。所以这段代码将页码位与高位分开,但不使用那些高位。这可能是因为它是一个简化的教学示例,实际部署代码会使用高位。
And why is using memset dangerous.
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
。这是错误的秘诀。
我发现了一个项目,我无法理解一段代码。Virtual memory
#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 很危险。
出于性能和内存原因,pageNumber
和 page
中的偏移量存储在单个 unsigned
值中。
我会在评论中用c++14
位表示加上0b
前缀来说明。
unsigned logicalAddress = someValue; // <- 0bPPPPPPPPFFFFFFFF
其中 P
表示 pageNumber
的位和 offsetNumber
的 F
位;
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
无论如何都会删除低位,因此使用 &
操作清除它们是没有意义的。所以这段代码将页码位与高位分开,但不使用那些高位。这可能是因为它是一个简化的教学示例,实际部署代码会使用高位。
And why is using memset dangerous.
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
。这是错误的秘诀。