Jessika’s CSC 373 Archived Resources

Tips

Binary:

The numbers we use on a day-to-day basis are decimal values, based on powers of ten. However, numbers can also be expressed in different ways, such as binary. A binary number is a value expressed in powers of two instead of powers of ten.

To convert a decimal number to a binary number, we first take into consideration the powers of twos and their corresponding decimal values:

23= 8 22 = 4 21 = 2 20 = 1

These represent the values held in each column of a binary number. A one in a column indicates counting the number towards the sum, while a zero means to ignore it. Thus, one can be represented as 0001, two as 0010, four as 0100, and eight as 1000.

Other decimal values can be made up using a combination of ones and zeros:

  • 5 = 0101
  • 6 = 0110
  • 10 = 1010

 

Hexadecimal:

Since binary data can be long and difficult to deal with, hexadecimal notation was developed to make representing binary easier. In hexadecimal notation, four bits (a nibble, 8 bits is a byte) can be represented using a single digit. The values of 0 – 9 and A – F are used to represent the values 0 – 15.

Decimal Hexadecimal Binary
0 0 0000
1 1 0001
2 2 0010
3 3 0011
4 4 0100
5 5 0101
6 6 0110
7 7 0111
8 8 1000
9 9 1001
10 A 1010
11 B 1011
12 C 1100
13 D 1101
14 E 1110
15 F 1111

0xFFFFFFFF is much easier to read and write than 1111 1111 1111 1111 1111 1111 1111 1111

 

Signed & Unsigned:

The difference between a signed and an unsigned integer is that a signed integer can represent either a positive or negative number while an unsigned integer can only represent positive number.

As we know, in the case of an unsigned (no negatives) integer, the binary value 1111 is representative of the decimal value 15.

However, in a signed (positives and negatives) integer, the leftmost bit will now represent a negative value:

23= -8 22 = 4 21 = 2 20 = 1

So the binary value 1111 will equal the decimal value -1. Therefore, the maximum positive value that a signed integer can represent is a zero followed by all ones, in this case 0111 = 7.

A standard integer in C will be signed. Unsigned integers have to be explicitly declared: unsigned int b;

 

Other Bitwise Operators:

Aside from left shifts and right shifts, there are a few other important bitwise operators to consider. These are and (&), or ( | ), not (~) and exclusive-or/xor (^).

This picture helps to summarize how each of these operators functions:

The “and” operator (&) returns a 1 only in columns where there are two 1s. All other combinations return a 0.

  •    10101010
  • & 11001100
  •    10001000

The “or” operator ( | ) returns a 1 in columns where there is at least one 1. Only the combination of two 0s returns a 0.

  •    10101010
  • | 11001100
  •    11101110

The “not” operator (~) simply reverses all bits, meaning that 1s will become 0s and vice-versa.

  •   ~ 10101010
  •      01010101

The “xor” operator (^) returns a 1 in columns where there is only 1. Columns with two 0s or two 1s will return a 0.

  •    10101010
  • ^ 11001100
  •    01100110

Pointers:

Pointers are variables that store or “point to” an address, where in memory some object or variable is stored.

Pointers are declared in C in the format type* typePtr; where type is the datatype of the variable (int, char, float, etc.) and typePtr is the name.

The following example initializes variable int i to 10 and stores the address of this variable in iPtr:

Dereferencing means to follow the pointer to the object or obtaining the value stored in a pointer’s address. This process also utilizes an asterisk.

dereference

What would the example above print? The address of the variable i and then the value stored there (10).

answer_ptr1

The exercise we went over in class had us write a program with two variables (int i and int* iPtr) that would return the values from 0 to 9 using a for loop without referring to int i except for initializing the value of iPtr. Code for that exercise:

 

Common assembly instructions are listed in the image below (click to view as larger):

Assembly

 

 

When converting from a decimal to a binary floating point value, there are three main parts that are necessary to take into consideration–the sign, the exponent value, and the mantissa.

In 32-bit systesms, the sign contains 1 bit, the exponent contains 7, and the mantissa contains the remaining 24.

In 64-bit systems, the sign contains 1 bit, the exponent contains 11, and the mantissa contains the remaining 52 bits.

floatingpoint

Let’s say the value we are converting from decimal to binary is 2.5. We will use a 32-bit system for this example.

To start, we first must write out 2 as binary. This is 0010. Next, we must write out .5 as binary. If we imagine there is a decimal point after 2 written in binary, then the next value after the decimal point is equivalent to 1/2, then 1/4, 1/8, 1/16, 1/32, and so on.

floating point place values

Therefore, .5 would just correspond with a 1 directly after the decimal point followed by all zeros: .100…

Putting the binary representation for 2 and .5 together, we get 0010.10 as the starting value.

Next, we move the decimal point to the right or left until we get a single 1 in front of the point. In this case, we move the decimal point once to the left, resulting in 1.010 x 2^1. The exponent 1 is positive since we must move the decimal point once to the right to obtain the original value.

Now, we store anything after the decimal point in 1.010 x 2^1 in the mantissa field, resulting in 010. Also, since we know that the number is positive, we can place a 0 in the sign field (1 if number were negative).

step1_2

Then, to get the exponent value, we take the exponent in the following value and add the bias to it: 1.010 x 2^1.

In a 32-bit system, the bias is 0111111. In a 64-bit system, the bias is 01111111111. In all cases, the bias will be a zero followed by all ones.

Adding exponent and bias:

  0000001

+ 0111111

  1000000

Therefore, the final value is 1000000. This is the value stored in the exponent field.

Our final result is:

final_floating_point

Here is a good website to use to verify your conversions from a base-10 to base-2 floating point!

1. The first program converts from decimal to hexidecimal using arithmetic and bitwise operators.

2. There are a few points to take away from this second program. Firstly, what #define means in the line #define N (32) is that N is set to the permanent value of 32. Anywhere N shows up in the rest of the program will have the value 32.

Next,

int comp(const void* p1, const void* p2) {

     return *((int*) p2) – *((int*) p1);

}

This function converts void* p1 and void* p2 into int* by casting using (int*) p2 and (int*) p1. Taking these two and placing an asterisk in front dereferences the pointer, meaning that p1 and p2 are followed to the address they point to and the value stored there is obtained. Overall, all this function is doing is subtracting the value in p1 from the value in p2.

Then, it is important to know what this line does:

int* array = malloc(N * sizeof(int));

malloc is a function that allocates a given amount of memory space on the heap. In this case, it would be N integers. Since we have the line #define N (32), we know that N is 32. So, in this malloc line, there is enough space for 32 integers allocated on the heap. 

Always remember that when you use malloc, you must use the free function at the end: free(array);

Finally, I wanted to remind everyone that an array pointer will always point to the starting address of an array. Therefore, in this line
while (p >= array)

the block executes just as long as p (defined as an int pointer) is greater than the starting address of the array. 


3. The assembly is already annotated line by line in the file. Common assembly instructions are given in Week 04 below. 


4. These two programs deal with a file that is shared between the producer and the consumer. The producer can create the file if it doesn't exist and read the file as well as write into it, as seen in this line: 

int outfile = open(sharedFile,                   /* name */
   	           O_CREAT | O_RDWR,             /* create, read/write */
   		   S_IRUSR | S_IWUSR | S_IXUSR | /* owner's rights */
   		   S_IROTH | S_IWOTH | S_IXOTH); /* others' rights */

Meanwhile, the consumer can only read it.
int infile = open(sharedFile, O_RDONLY);


Sizes of Data Types:

datatypesize

Formatting:

formatting


Videos and Handouts

Leave a Reply

Your email address will not be published. Required fields are marked *