I’m BACK!!! This blog has started to get ranked quite high on SEO for cs50 over the past 6 months which has intrigued me and almost lured me back. Now that I’ve started up Madhat Girls I figured that I really need to invest more time into learning how to code.
So, after watching 2 hours of a very entertaining lecture by El Famoso David I’ve been set this new task of answering what each of these things are (below). Uhoh, so I had a read and I am confused AF so here’s me just listing the research into a digestible simplified way. Please correct me if I’m wrong or even guide me towards better answers.
Table of Contents
(Click to go to explanations)
- What is stdin.t?
- Why do we use uint8_t, uint32_t, int32_t, and uint16_t in a program?
- How many bytes is a BYTE, a DWORD, a LONG, and a WORD?
- What must the first two bytes of any BMP file be?
- What’s the difference between bfSize and biSize?
- What does it mean if biHeight is negative?
- What field in BITMAPINFOHEADER specifies the BMP’s color depth ?
- Why might fopen return NULL in copy.c?
- Why is the third argument to fread always 1 in our code?
- What value does copy.c assign to padding if bi.biWidth is 3?
- What does fseek do?
- What is SEEK_CUR?
If you want your program to work across any system environment you can not be sure the actual size of an int will ALWAYS be 32 bits (for example). If you use stdint.h header files you can use fixed-width integer type int32_t, which is guaranteed to have 32 bits on any system environment as it refers back to the library for the information. So defining various integer types in a global library can help our program to work universally. With this, we can be more specific in what we require for each integer.
Answer: It is a C Standard Library that contains functions that have been tested, optimised for performance, saves development time and is portable.
What’s the point of using uint8_t, uint32_t, int32_t, and uint16_t in a program?
These are the types of data used in C programming.
Main Data Types
- integer (fixed-point)
In order for me to answer this question, I needed to re-understand why we use int data types. It’s explained in the cs50 lecture but I needed a deeper understand and so I found this youtube video that clearly explains why we use signed and unsigned and how it changes the int’s range and allows negatives values (signed int).
The difference between a signed and unsigned integer
- Unsigned can hold a larger positive value and no negative value.
- Unsigned uses the first bit as a part of the value
- Signed version uses the first bit to identify whether the number is positive or negative.
- Signed integers can hold both positive and negative numbers
- Signed integers range are lower than unsigned
n = bits min - max values signed = -2(n-1)-1 to 2(n-1)-1 unsigned = 0 to 2(n)-1 The int is 4 bytes in size or 32 bits because 1 byte = 8 bits, therefore, there are 8 x 4 bytes = 32-bit ints. n = 32 bits max value signed 32 bit = to 231- 1 = 4294967295 max value unsigned 32 bit = 232-1 = 4,294,967,296
So that’s an int, what’s a char?
The char data type is commonly used to represent a character and is also used when a very small amount of space, typically one byte, is needed to store a number. A signed char can store a number from -128 to 127, and an unsigned char can store a number from 0 to 255. When used to represent a character a signed or unsigned is irrelevant.
// 1 byte -> [0-255] or [0x00-0xFF] uint8_t number8 = testValue; // 255 unsigned char numberChar = testValue; // 255 // 2 bytes -> [0-65535] or [0x0000-0xFFFF] uint16_t number16 = testValue; // 65535 unsigned short numberShort = testValue; // 65535 // 4 bytes -> [0-4294967295] or [0x00000000-0xFFFFFFFF] uint32_t number32 = testValue; // 4294967295 unsigned int numberInt = testValue; // 4294967295 // 8 bytes -> [0-18446744073709551615] or [0x0000000000000000-0xFFFFFFFFFFFFFFFF] uint64_t number64 = testValue; // 18446744073709551615 unsigned long long numberLongLong = testValue; // 18446744073709551615
Char is not another type of int, as it can store a much smaller range of numbers. For instance, while an int can store the number 1,000, a char cannot.
Unsigned char is not guaranteed to be an 8-bit type whereas uint8_t is guaranteed (if available).
Answer: Every variable used in the source code needs to be declared by setting its data type. By assigning a certain data type to a variable we define several aspects linked to the variable. We do this so that 1) the compiler or interpreter can understand how the programmer intends to use the data and 2) for memory allocation. Every data type has a memory size associated with it. So when suitable daa types are used we can optimise the use of memory.
Aspects Linked to Variable
- the memory size to be allocated to store the content of the variable
- the types of operations that can be performed on the variable
- the restrictions which are applied in terms of operations
How many bytes is a BYTE, a DWORD, a LONG, and a WORD, respectively?
What (in ASCII, decimal, or hexadecimal) must the first two bytes of any BMP file be? Leading bytes used to identify file formats (with high probability) are generally called “magic numbers.”
The first 2 bytes of the BMP file format are the character “B” then the character “M” in ASCII encoding. Letters are represented by their ASCII value. ‘B’ is decimal 66 (hex 42). ‘M’ is decimal 77 (hex 4d). This is 0x42 and 0x4D respectively in Hexadecimal.
Answer: The first 2 bytes of the BMP file in ASCII, decimal, and hexadecimal are: B, M; 66, 77; and 0x42, 0x4d.
What’s the difference between bfSize and biSize?
biSize is the number of bytes required by the BITMAPINFOHEADER structure. The BITMAPINFOHEADER structure cont ains information about the type, size, and layout of a file that contains a DIB.
bfsize is the size of the bitmap file in bytes and is found within the BITMAPFILEHEADER. The BITMAPFILEHEADER structure contains information about the dimensions and color format of a DIB.
Answer: The difference between the two is that bfsize is the size of the whole bitmap file whereas biSize is the number of bytes needed just by the BITMAPINFOHEADER.
What does it mean if biHeight is negative?
biHeight specifies the height of the bitmap, in pixels.
Device-Independent Bitmap (DIB) is a graphics file format used by Windows. The files are bitmapped graphics that represent color formats. It’s similar to .BMP format but they have a different header. DIB files can be opened and edited in most image editing programs.
If biHeight is positive, the image buffer starts with the bottom row of pixels, followed by the next row up, and so forth. The top row of the image is the last row in the buffer and its origin is the lower-left corner.
In the Graphics Device Interface (GDI), all DIBs are bottom-up. The following diagram shows the physical layout of a bottom-up DIB.
If the image is stored top-to-bottom the height of a BMP image can be negative. So, when figuring out the size of the image, negative doesn’t make sense, so it should be the absolute value of the height.
Answer: If biHeight is negative, the bitmap is a top-down DIB and its origin is the upper-left corner. If biHeight is negative, indicating a top-down DIB. Note: Top-down DIBs cannot be compressed.
What field in BITMAPINFOHEADER specifies the BMP’s color depth (i.e., bits per pixel)?
The number of bits-per-pixel. The biBitCount member of the BITMAPINFOHEADER structure determines the number of bits-per-pixel; these define each pixel and the maximum number of colors in the bitmap.
Why might fopen return NULL in copy.c?
If the file doesn’t already exist the program will create the file and store it in the current working directory. If the computer cannot allocate enough memory to create the desired file, NULL would be returned. Also, there may be a permissions error when trying to write to an open file, or you may not have access.
Why is the third argument to fread always 1 in our code?
The syntax for fread() is:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
The code in cs50 is:
fread(&bi, sizeof(BITMAPINFOHEADER), 1, inptr);
- buffer: it specifies the pointer to the block of memory with a size of at least (size*count) bytes to store the objects.
- size: it specifies the size of each object in bytes. size_t is an unsigned integral type.
- count: it specifies the number of elements, each one with a size of size bytes.
- stream: it specifies the file stream to read the data from.
The fread() function is commonly used to read the block of data from stream. size*count which is the third argument in fread is the count argument that holds the maximum number of items to be read.
If the third argument is one then 1 block will read 1 byte (assuming it will be successful), if the sizeof(BITMAPINFOHEADER) is 3 then 3 bytes will be read for 1 block.
Answer: The fread() function reads 1 block of sizeof(BITMAPINFOHEADER), which is 40, and then it will be read from intpr written into &bi where it specifies for the pointer to the block of memory to. It will always read 1 in our code as it
What value does copy.c assign to padding if bi.biWidth is 3?
The size of RGBTRIPLE is 3 as it is in the 54, 55 and 56th byte on the disk.
int padding = (4 - (bi.biWidth * sizeof(RGBTRIPLE)) % 4) % 4; int padding = (4 - ( 3 * 3 ) ) %4 ) % 4 = 3; int padding = 3;