简体   繁体   English

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

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

I found one project where I can't uderstand one piece of code.我发现了一个我无法理解一段代码的项目。 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;
}

I can't understand these three lines.我看不懂这三行。

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

As I understand papeNumber is value where logicalAddress and pageNuberMask a stored together.据我了解, papeNumber 是 logicalAddress 和 pageNuberMask 存储在一起的值。 And this char & join them.而这个字符 & 加入他们。 Then we do offset on 8(>> 8).然后我们在 8(>> 8) 上做偏移。

And why is using memset dangerous.以及为什么使用 memset 很危险。

For performance and memory reasons pageNumber and offset in the page are stored in single unsigned value.出于性能和内存原因, page中的pageNumber和偏移量存储在单个unsigned值中。

I will use c++14 bit representation with 0b prefix in comments to explain.我将在注释中使用带有0b前缀的c++14位表示来解释。

unsigned logicalAddress = someValue;           // <- 0bPPPPPPPPFFFFFFFF

where P denotes bits for pageNumber and F bits for offsetNumber ;其中P表示用于比特pageNumberF为比特offsetNumber ;

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

About memset using it is not dangerous if used correctly.关于memset如果使用得当,使用它是没有危险的。

(For purposes of illustration, this answer assumes the addresses are 32 bits, which appears to be consistent with the code in the question.) (出于说明目的,此答案假定地址为 32 位,这似乎与问题中的代码一致。)

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

The logical address is partitioned into three sets of bits: 16 upper bits that are ignored in this code, 8 bits used for a page number, and 8 lower bits that are used for an offset within a page.逻辑地址被划分为三组位:在此代码中忽略的 16 位高位、8 位用于页号,以及 8 位低位用于页面内的偏移量。

pageNumberMask is a value that has been prepared to have 1s in the page number bits and 0s elsewhere. pageNumberMask是一个已准备好在页码位中为 1,在其他地方为 0 的值。 Then the operation logicalAddress & pageNumberMask performs a bitwise AND, which produces a value in which the only bits set are those that were set in the page number bits of logicalAddress .然后操作logicalAddress & pageNumberMask执行按位与,它产生一个值,其中设置的唯一位是在logicalAddress的页码位中设置的位。 In other words, it produces a value in which the upper bits and the offset bits are cleared, effectively isolating the page number bits.换句话说,它产生一个值,其中高位和偏移位被清除,有效地隔离了页码位。

Then pageNumber >> 8 shifts those page number bits down to the low bits, so the result is a page number.然后pageNumber >> 8将这些页码位向下移动到低位,因此结果是页码。 That page number can then be used to index arrays.然后可以使用该页码来索引数组。

Similarly, offsetMask is a prepared value with 1s in the offset bits and 0s elsewhere, and logicalAddress & offsetMask extracts just the offset bits.类似地, offsetMask是一个准备好的值,偏移位中为 1,其他地方为 0,并且logicalAddress & offsetMask仅提取偏移位。

Note that logicalAddress & pageNumberMask serves a purpose only if bits above the page number bits might be set.请注意,仅当可以设置页码位以上的位时, logicalAddress & pageNumberMask才有用。 This is because pageNumber >> 8 removes the lower bits anyway, so there is no point in clearing them with an & operation.这是因为pageNumber >> 8无论如何都会删除低位,所以用&操作清除它们是没有意义的。 So this code separates the page number bits from the upper bits but makes no use of those upper bits.所以这段代码将页码位与高位分开,但不使用这些高位。 This might be because it is a simplified example for teaching, and actual code for deployment would make use of the upper bits.这可能是因为它是一个简化的教学示例,实际部署代码会使用高位。

And why is using memset dangerous.以及为什么使用 memset 很危险。

memset is a powerful routine that is easy to use incorrectly. memset是一个功能强大的例程,很容易被错误地使用。 Given incorrect arguments, it will modify any accessible memory, and the compiler often cannot detect that it has been used incorrectly, so it cannot provide a warning or error message.给定不正确的参数,它将修改任何可访问的内存,并且编译器通常无法检测到它被错误地使用,因此它无法提供警告或错误消息。

Defects in the Code代码中的缺陷

The code in the question has a number of defects, so it is not a great example for teaching:问题中的代码有很多缺陷,因此它不是一个很好的教学示例:

  • struct tlbTable tlb[TLB_SIZE]; followed by memset(pageTable, -1, 16*sizeof(char));后跟memset(pageTable, -1, 16*sizeof(char)); looks like a bug.看起来像一个错误。 pageTable was initialized previously, and this was probably intended to initialize tlb . pageTable之前已初始化,这可能是为了初始化tlb And the size is wrong;而且尺码不对; tlb has 16 elements ( TLB_SIZE is 16), and each is several bytes. tlb有 16 个元素( TLB_SIZE为 16),每个元素是几个字节。 That line should probably be memset(tlb, -1, sizeof tlb);该行应该是memset(tlb, -1, sizeof tlb); , and the previous memset should be memset(pageTable, -1, sizeof pageTable); , 而之前的memset应该是memset(pageTable, -1, sizeof pageTable); . .
  • Preprocessor macros are defined for various parameters, such as 256 for PAGE_SIZE , but then parts of the code ignore these and use hard-coded constants, as in Frame*256 + Index .预处理器宏是为各种参数定义的,例如PAGE_SIZE为 256 ,但部分代码会忽略这些并使用硬编码常量,如Frame*256 + Index This is a recipe for bugs.这是错误的秘诀。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM