for (uint8_t pos = 0; pos < nToPrint; pos++) {
fprintf(Out, " %02X", Base[Index + pos]);
}fprintf(Out, "\n");
}CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 2Suppose we executed the call: showBytesAtIndex(stdout, Data, 34, 6)Now, Data[34] would be the byte 36 near the beginning of the second row of the display, and the function would print 6bytes starting there, with two spaces separating the bytes: 36 DA DC 07 CF 2B(Remember, a hex nybble is a 4-bit value, so there are two nybbles, and hence two hex digits, per byte.)Let's consider a few details in the implementation of that function: We used const in specifying the second parameter. That means the function is not allowed to modify thecontents of the array that's passed to it. We refer to the bytes in the memory block using the type unit8_t; that's so we can avoid any issues that mightarise if the high bit of a byte happened to be 1 (remember 2's complement representation). The parameter Index is of type uint16_t; that limits the size of the memory block. The maximum value of auint16_t variable is 216 – 1 or 65535. There's no good reason for that, really. It just gave me an excuse to addthis to the discussion. A similar point could be made about the parameter nToPrint. The format string " %02X" causes the variable to be displayed in two columns, with a leading 0 if necessary, inhexadecimal, preceded by two spaces.But the memory display shown above is not very human-friendly. A more readable version would format the data so theindividual bytes were separated, and indicate the offsets of those bytes as offsets relative to the beginning of the block: 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 7F 10 22 EC 2B EA D1 F5 4E 92 62 89 7A 7E 39 03 1 9E F2 0A 22 F8 4A E7 F2 8A 40 24 1B CA 9E D0 49 2 AF F2 36 DA DC 07 CF 2B 99 32 DF 9D FD A2 D1 9B 3 94 DB BD 8D 26 A4 7F B0 E5 A4 CB AF 42 9B F8 F1 4 8E 2E CC 6A 35 9B 95 CE CD 74 6B CA 16 3C 66 AB 5 18 23 38 3E C8 B7 EE AD 5B B9 5C 9E 0B D8 86 E2 6 83 5B 4D B8 F7 E2 87 C4 57 F2 8F 6D 2F F5 18 47 7 18 50 85 E0 08 73 8D 63 2C E9 01 80 3E 91 63 C1 8 EC B0 79 E3 92 00 A8 E9 F3 37 57 22 2C 6F 69 44 9 C0 EE 25 C8 61 B2 2B 8D 9C 2D 0D DA BE 70 9B AA A 62 79 74 65 15 36 9C 08 6D F3 2A 99 63 93 DD 23 B 81 02 EB E2 B5 16 6F 89 7A 7C 2B 01 ED C6 AC 0D C DA 3A C0 EF 70 5D F7 DD 50 21 76 B3 B4 53 D6 35 D 56 C1 17 0B D8 86 5C 1B 03 87 1D F0 4D C9 FD 27 E 03 BE 17 73 1B 0E 50 6B 30 C6 1F E4 19 F5 1A 6F F B7 31 7A 8F B8 D6 AA BB 5D C7 AB AA 90 A8 D2 93 10 66 E9 06 81 F7 56 ED 27 1C 0C 0C 36 01 26 A5 B8 11 57 20 47 0F F6 F2 CA 54 B9 75 FE 4A 1E D0 DD 84 12 89 7A 7E 39 03 F3 D8 57 FF E4 8D 00 0A 32 B9 62 13 52 00 71 49 F2 3C 9D AC B1 9B F6 CF 6C D3 54 25 14 B7 5A D6 F2 4D AF 49 4C 93 D6 4C 9E 08 05 00 5B 15 06 71 A4 F8 AD 41 A4 5F DC 9A 2E 48 6E 82 6E 25 16 2C E9 01 80 3E 91 63 C1 81 02 EB E2 B5 16 6F 89 17 DC 44 0B D8 F3 60 75 87 36 C2 25 3F C7 25 9A CD 18 96 3E C6 44 7F 6A A3 5B 05 D1 A4 73 54 12 98 30 19 26 A4 7F B0 E5 A4 CB AF 39 03 47 54 68 2D 0D DA 1A 56 B0 5A 4A 10 CF D1 47 91 F6 0B D8 86 20 26 B1 1B 5E EC F5 DD 57 98 38 5C 6A DC CF BE EE 67 EE 45 1C 17 48 8F 28 18 60 6F A9 56 F5 02 71 15 29 22 73 1D 15 18 50 6C B0 88 C8 1A 65 97 D8 53 FF C7 98 16 1E 0F 27 3E 27 87 AD D1 DD A2 D3 4E B7 FC 71 2A 12 1F 89 7A 7E 39 03 47 54 68 2D 0D DA B7 5A D6 FD A2This is known as a hexdump view. The value in the first column shows the first two (hex) digits of the offset of the datadisplayed in that row. The column heading for a byte shows the last digit of the offset of that byte.0x10 at offset 0x01 or 1100x4A at offset 0x15 or 21100xAA at offset 0xFB or 251100x39 at offset 0x1F3 or 49910CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 3The FunctionsFor this assignment, you'll implement three C functions to perform different kinds of accesses to a block of memory. Besure to pay attention to the restrictions that are imposed on your implementation. In particular, each function is restricted tousing pointer notation to manage all accesses to the data; use of array bracket notation will result in a score of 0.The first function you will implement is functionally equivalent to the example function given earlier, but it will use pointersyntax instead of array syntax:/** Uses pointer-based logic to access a specified portion of a region of* memory and copy the corresponding bytes to a supplied array.** Pre: pDest points to an array of dimension nBytes + 1, or greater* baseAddr points to the first byte of the memory region* Offset is the location, relative to baseAddr, of the first* relevant byte of the memory region* nBytes is the number of bytes to be copied* Restrictions:* You must use only pointer syntax in accessing the data block.*/void getBytesAtOffset(uint8_t* const pDest, const uint8_t* const baseAddr, uint16_t Offset, uint8_t nBytes);The interface of the function deserves a short discussion. The second parameter, baseAddr, illustrates the use of constin two different ways. For a pointer used as a parameter, placing const before the pointer type means the function is notpermitted to modify the value of the target of the pointer, and placing const after the pointer type means the function isnot permitted to modify the value of the parameter (which would make it point to a different target).In this case, we don't what this function to modify the contents of the memory block; the first use of const enforces that.And, we don't see any reason for the function to work with a pointer that has a different target than we have decided on, sothe second use of const enforces that.It's good practice to use const appropriately when designing function interfaces, especially when a parameter is a pointer.Even so, you should also understand that the C language does make it possible for a programmer to create a local pointer,initialize it from the parameter, and use that local pointer in ways that violate the const restrictions you may haveimposed. That doesn't make const useless, and a principled C programmer will avoid sidestepping const.Here are some example results, based on the memory block shown earlier, assuming *baseAddr is the first byte:getBytesAtOffset(..., baseAddr, 23, 4): F2 8A 40 24getBytesAtOffset(..., baseAddr, 219, 2): F0 4DgetBytesAtOffset(..., baseAddr, 338, 12): A4 F8 AD 41 A4 5F DC 9A 2E 48 6E 82By the way, the parameters in the examples above are given in base 10; if you want to check the results against thehexdump, you may want to convert the offsets to hex as well. The first one would be 0x17.We guarantee that testing will only be done with logically valid parameters.CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 4The second function requires traversing the given memory region and looking for matches to a given one-byte value:/** Uses pointer-based logic to search a specified portion of a region of* memory for occurrences of a specified one-byte value.** Pre: pOffsets points to an array of dimension at least 256* baseAddr points to the first byte of the memory region* Length is number of bytes in the memory region* Byte is the value to be found* Post: The offsets of up to 256 occurrences of Byte have been stored* in pOffsets, in ascending order, starting at index 0.* Returns: the number of occurrences of Byte found in the memory region* (which may be less than the actual number of occurrences)* Restrictions:* You must use only pointer syntax in accessing the data block.*/uint8_t findOccurrencesOfByte(uint16_t* const pOffsets, const uint8_t* const baseAddr, uint32_t Length, uint8_t Byte);Here are some example results, based on the memory block shown earlier, assuming *baseAddr is the first byte:findOccurrencesOfByte(..., baseAddr, 512, 0x7F): 0 36 184 192findOccurrencesOfByte(..., baseAddr, 512, 0): 85 12B 131 14EfindOccurrencesOfByte(..., baseAddr, 512, 0xE9): 79 87 101 161 0 1 2 3 4 5 6 7 8 9 A B C D E F 0 7F 10 22 EC 2B EA D1 F5 4E 92 62 89 7A 7E 39 03 1 9E F2 0A 22 F8 4A E7 F2 8A 40 24 1B CA 9E D0 49 2 AF F2 36 DA DC 07 CF 2B 99 32 DF 9D FD A2 D1 9B 3 94 DB BD 8D 26 A4 7F B0 E5 A4 CB AF 42 9B F8 F1 4 8E 2E CC 6A 35 9B 95 CE CD 74 6B CA 16 3C 66 AB 5 18 23 38 3E C8 B7 EE AD 5B B9 5C 9E 0B D8 86 E2 6 83 5B 4D B8 F7 E2 87 C4 57 F2 8F 6D 2F F5 18 47 7 18 50 85 E0 08 73 8D 63 2C E9 01 80 3E 91 63 C1 8 EC B0 79 E3 92 00 A8 E9 F3 37 57 22 2C 6F 69 44 9 C0 EE 25 C8 61 B2 2B 8D 9C 2D 0D DA BE 70 9B AA A 62 79 74 65 15 36 9C 08 6D F3 2A 99 63 93 DD 23 B 81 02 EB E2 B5 16 6F 89 7A 7C 2B 01 ED C6 AC 0D C DA 3A C0 EF 70 5D F7 DD 50 21 76 B3 B4 53 D6 35 D 56 C1 17 0B D8 86 5C 1B 03 87 1D F0 4D C9 FD 27 E 03 BE 17 73 1B 0E 50 6B 30 C6 1F E4 19 F5 1A 6F F B7 31 7A 8F B8 D6 AA BB 5D C7 AB AA 90 A8 D2 93 10 66 E9 06 81 F7 56 ED 27 1C 0C 0C 36 01 26 A5 B8 11 57 20 47 0F F6 F2 CA 54 B9 75 FE 4A 1E D0 DD 84 12 89 7A 7E 39 03 F3 D8 57 FF E4 8D 00 0A 32 B9 62 13 52 00 71 49 F2 3C 9D AC B1 9B F6 CF 6C D3 54 25 14 B7 5A D6 F2 4D AF 49 4C 93 D6 4C 9E 08 05 00 5B 15 06 71 A4 F8 AD 41 A4 5F DC 9A 2E 48 6E 82 6E 25 16 2C E9 01 80 3E 91 63 C1 81 02 EB E2 B5 16 6F 89 17 DC 44 0B D8 F3 60 75 87 36 C2 25 3F C7 25 9A CD 18 96 3E C6 44 7F 6A A3 5B 05 D1 A4 73 54 12 98 30 19 26 A4 7F B0 E5 A4 CB AF 39 03 47 54 68 2D 0D DA 1A 56 B0 5A 4A 10 CF D1 47 91 F6 0B D8 86 20 26 B1 1B 5E EC F5 DD 57 98 38 5C 6A DC CF BE EE 67 EE 45 1C 17 48 8F 28 18 60 6F A9 56 F5 02 71 15 29 22 73 1D 15 18 50 6C B0 88 C8 1A 65 97 D8 53 FF C7 98 16 1E 0F 27 3E 27 87 AD D1 DD A2 D3 4E B7 FC 71 2A 12 1F 89 7A 7E 39 03 47 54 68 2D 0D DA B7 5A D6 FD A2CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 5The third function requires exploiting pointer typecasts in order to impose a specified interpretation on a segment of data inmemory. You should be sure you review and understand the notes on that topic; reading the short tutorial on the Resourcespage of the course website will help.Consider the four bytes at the address 0xA0 in the hexdump: 62 79 74 65We could interpret those four bytes in a number of different, conflicting ways. They could be interpreted as four extendedASCII codes ('b', 'y', 't', 'e'). They could be interpreted as a 32-bit floating-point number (a float in C or Java). Theycould be interpreted as a 32-bit signed integer or a 32-bit unsigned integer. Let's consider that in a bit more detail.As ASCII codes, the four bytes represent the characters 'b', 'y', 't', and 'e', respectively. Numeric values are stored in littleendianorder on x86 systems, so as an integer value, those four bytes will be interpreted as 0x65747962. As a signedinteger (2's complement representation), that yields the value 170213206610. As an unsigned integer (base-2representation), that yields the same value, since the high bit is 0We will also use an enumerated type to indicate to the function whether it should interpret the specified segment of data asa signed integer or an unsigned integer:enum _Sign {SIGNED, UNSIGNED};typedef enum _Sign Sign;Enumerated types (also available in Java) allow you to define a custom type whose values are descriptive labels, which canmake your code much easier to understand. Without the typedef statement, we'd have to declare variables of this type asenum _Sign; the typedef statement allows us to declare them as Sign, which is more convenient./** Uses pointer-based logic to compute the sum of two values taken from a* region of memory, using pointer typecasts to control the number of bytes* that are summed, and the way those bytes are interpreted.** Pre: pDest points to a memory region large enough to hold the* requested value* baseAddr points to the first byte of the memory region* Offset1 is the location, relative to baseAddr, of the first* byte of the first operand* Offset2 is the location, relative to baseAddr, of the first* byte of the second operand* Sign indicates whether the bytes are to be interpreted as* representing signed or unsigned integers* nByte is the number of bytes to be considered (1, 2, 4, or 8 only)* Post: *pDest holds the sum of the two specified values* Returns: false if either of the requested values could not be obtained;* true otherwise* Restrictions:* You must use only pointer syntax in accessing the data.*/bool sumValuesAtOffsets(void* pDest, const uint8_t* const baseAddr, uint32_t Offset1, uint32_t Offset2, Sign Sgn, uint8_t nBytes);For example, suppose we have the data block shown earlier, and the function is called with baseAddr pointing to thebeginning of the block, Offset1 == 0x148, Offset2 == 0xA4, Sgn == SIGNED, and nBytes == 2.Now, Offset1 points to the bytes 93 D6, which represent the signed value 0xD693 (which is -1060510).And, Offset2 points to the bytes 15 36, which represent the signed value 0x3615 (which is 1384510).Therefore, the sum of the two values is 0x0CA8 (which is 324010).CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 6Here's another example, based on the memory block shown earlier, assuming *baseAddr is the first byte:sumValuesAtOffsets(..., baseAddr, 0x74, 0x8C, UNSIGNED, 4): 281797483610In this case:Offset Bytes Value10 Sum10----------------------------------------------------0x74 08 73 8D 63 16702144080x8C 2C 6F 69 44 1147760428 2817974836As a signed value, this would have yielded -147699246010.It's also worth discussing the use of void* as the type of the first parameter. Since Sgn can be either SIGNED orUNSIGNED, and nBytes can be any of 1, 2, 4 or 8, the value we are requesting could be any of 8 different C types.Rather than supply 8 different parameters, only one of which would be used in any particular call, we take a genericapproach. A void* can point to data of any type, so the caller can create an appropriate variable, pass a generic pointer toit, and the function can use that generic pointer (by casting) to set the caller's variable to the correct value.The positive aspect of this use of void* is that it simplifies the function interface, at the expense of some pointer casts onthe part of the caller and the function. The negative aspect is that there is a complete loss of type-checking, so if the callerdoes not prepare a "receptacle" of the type indicated by the parameters, there will be no guarantee of a useful error message,from the compiler, or at runtime.TestingDownload c05Files.tar from the course website and unpack in a CentOS 7 directory; you will find these files:c05driver.c driver for testing/grading codePtrFuncs.h declarations for functions specified in this assignmentTestCode.h declarations for public test/grading functionsTestCode.o 64-bit Linux binary for testing/grading codeGenerator.h declarations for data block generation and outputGenerator.o 64-bit Linux binary for data block generation and output codeYou must create a C source file PtrFuncs.c to hold your implementations of the specified functions.You can compile the program with the following command:CentOS> gcc –o c05driver –std=c11 –Wall -W c05driver.c PtrFuncs.c TestCode.o Generator.oThe test driver can be executed with the command:CentOS> ./driver [-all | -get | -find | -sum]The various optional switches determine which functions are tested (-all is the default). By default, each execution ofdriver will produce a different set of test data, unless you use the –repeat switch:CentOS> ./driver [-all | -get | -find | -sum] [-repeat]In that case, the test data file created by a previous run will be reused. That allows you to focus on a fixed set of test caseswhile you are debugging. In fact, you could even edit an existing test case file and create test cases as you like, and thenuse the –repeat switch to use those test cases.CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 7The driver will also create a file, DataBlock.txt, which contains a hex dump of the specific memory region generatedfor the test run. You may find that useful when debugging your results.You should test your solution thoroughly; the given testing code generates random test data, and there is no guarantee thatit will cover all cases unless you run it a number of times.What to SubmitYou will submit your modified version of the file PtrFuncs.c to the Curator, this time via the collection point C05.That file must include any helper functions you have written and called from your implementations of the various specifiedfunctions; any such functions must be declared (as static) in the file you submit. You must not include any extraneouscode (such as an implementation of main() in that file).Your submission will be graded by running the supplied test/grading code on it. A TA will also check to see if yoursolution violates any of the restrictions given in the header comment for the function; if so, your submission will beassigned a score of zero (0), regardless of how many tests it passes.Pledge:Each of your program submissions must be pledged to conform to the Honor Code requirements for this course.Specifically, you must include the following pledge statement in the submitted file:// On my honor://// - I have not discussed the C language code in my program with// anyone other than my instructor or the teaching assistants// assigned to this course.//// - I have not used C language code obtained from another student,// the Internet, or any other unauthorized source, either modified// or unmodified.//// - If any C language code or documentation used in my program// was obtained from an authorized source, such as a text book or// course notes, that has been clearly noted with a proper citation// in the comments of my program.//// - I have not designed this program in such a way as to defeat or// interfere with the normal operation of the Curator System.////// <Student Name>// <Student's VT email PID>We reserve the option of assigning a score of zero to any submission that is undocumentedor does not contain this statement.Change LogVersion Posted Pg Change4.00 Mar 6 Base document.CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 8Appendix I: Brief tutorial on using pointer arithmetic and pointer typecasts in CFirst of all, you must understand the effect and uses of a pointer typecast. Consider the following snippet:uint16_t *x = malloc(sizeof(uint16_t)); // 1*x = 684; // 2Statement 1 causes the allocation of a two-byte region of memory, whose address is stored in the pointer x. Statement 2stores the value 684 (0x2AC in hexadecimal, or 0000 0010 1010 1100 in binary) into that two-byte region. Let'sassume that the address returned by the call to malloc() was 0x00008192.So the current situation in memory would be:(The bytes are stored in little-endian order, just as they would be on any Intel-compatible system.) If you dereference thepointer x, you'll obtain the contents of the two bytes beginning at the address stored in x. That's because x was declared asa pointer to something of type uint16_t, and sizeof(uint16_t) is 2 (bytes).Now consider:uint8_t *y = NULL; // 3: y == 0x00000000y = (uint8_t*) x; // 4: y == 0x00008192uint8_t z = *y; // 5: z == 0xAC (1 byte)uint16_t w = *x; // 6: w == 0x02AC (2 bytes)The effect of statement 4 is that y takes on the same value as x; pointer variables are 32 bits wide, regardless of the type oftarget they may take, and so the value of x will fit neatly into y. So, why the typecast? Simply that C is somewhat pickyabout assigning a pointer of one type to a pointer of another type, and the typecast formalizes the logic so that the compilerwill accept it. If you dereference y, you'll obtain the contents of the single byte at the address stored in y, sincesizeof(uint8_t) is 1. Hence, statement 5 will assign the value 0xAC or 172 to z, but statement 6 will assign thetwo-byte value 0x02AC or 684 to the variable w.1010 1100 0000 0010low byte(at lowaddress)high byte(at nextaddress)x 92810000theHeap theStackA C 0 2CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 9Here's a brief summary:Note how we can use the type of a pointer to determine how many bytes of memory we obtain when we dereference thatpointer, as well as how those bytes are interpreted. This can be really useful.The second thing to understand is how pointer arithmetic works. Here is a simple summary:T *p, *q; // Take T to represent a generic type.. . . // Assume p gets assigned a target in here.q = p + K; // Let K be an expression that evaluates to an integer.Then the value of q will be: p + K * sizeof(T). Note well: this is very dangerous unless you understand how tomake use of it. In some respects, this is really quite simple; maybe too simple. The essential thing you must alwaysremember is that if you want to move a pointer by a specific number of bytes, it's simplest if the pointer is a char* oruint8_t*, since the arithmetic will then provide you with byte-level control of the pointer's logical position in memory.The following loop would walk the pointer y through the bytes of the target of x (the uint16_t* seen earlier):uint8_t *y = (uint8_t*) x;uint32_t bytesRead = 0;while ( bytesRead < sizeof(uint16_t) ) { printf("%"PRIx8"\n", *y); // print value of current byte in hex; // 'x' causes output in hex;// 'X' capitalizes the hex digits ++y; // step to next byte of target of x ++bytesRead;}p*(uint8_t*)p*(uint16_t*)p*(uint64_t*)p*(uint32_t*)p434317431700A2431700A298BB0C80CS 2505 Computer Organization I C05: Pointers in CVersion 4.00 This is a purely individual assignment! 10You can also achieve the same effect by applying an offset to the pointer instead of incrementing the pointer:. . . // same code as before printf("%"PRIx8"\n", *(y + bytesRead)); // y + bytesRead points to a // location bytesRead bytes // past where y points ++bytesRead; // increment your offset counter}The second approach works because y + bytesRead is a uint8_t* that "walks" through memory byte-by-byte asbytesRead is incremented.You might want to experiment with this a bit…Now for copying values from memory into your variables (which are also in memory, of course)... The simplest approachis use appropriate variable types and pointer typecasts. Suppose that the uint8_t pointer p points to some location inmemory and you want to obtain the next four bytes and interpret them as an int32_t value; then you could try these:int32_t N = *p; // NO. This takes only 1 byte!int32_t *q = (int32_t*) p; // Slap an int32_t* onto the location;int32_t N = *q; // so this takes 4 bytes as desired.int32_t N = *((int32_t*) p); // Or do it all in one fell swoop.
The last form is the most idiomatic in the C language; it creates a temporary, nameless int32_t* from p and thendereferences it to obtain the desired value. Note that this doesn't change the value of p, and therefore does not changewhere p points to in memory. So, if you wanted to copy the next few bytes you'd need to apply pointer arithmetic to movep past the bytes you just copied:p = p + sizeof(int32_t); // Since p is a uint8_t*, this will move p forward // by exactly the size of an int32_t.One final C tip may be of use. The C Standard Library includes a function that will copy a specified number of bytes fromone region of memory into another region of memory: memcpy(). You can find a description of how to use the functionin any decent C language reference, including the C tutorial linked from the Resources page of the course website.The C Standard, section 6.5.6 says:When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointeroperand. If the pointer operand points to an element of an array object, and the array is large enough, the result pointsto an element offset from the original element such that the difference of the subscripts of the resulting and originalarray elements equals the integer expression. In other words, if the expression P points to the i-th element of an arrayobject, the expressions (P)+N (equivalently, N+(P)) and (P)-N (where N has the value n) point to, respectively,the i+n-th and i?n-th elements of the array object, provided they exist. Moreover, if the expression P points to the lastelement of an array object, the expression (P)+1 points one past the last element of the array object, and if theexpression Q points one past the last element of an array object, the expression (Q)-1 points to the last element ofthe array object. If both the pointer operand and the result point to elements of the same array object, or one past thelast element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. Ifthe result points one past the last element of the array object, it shall not be used as the operand of a unary * operatorthat is evaluated.
因为专业,所以值得信赖。如有需要,请加QQ:99515681 或邮箱:
微信:codinghelp