Here you'll find all the code I've written in the W09A tutorials, as well as some possibly useful information:
cs1521@cse.unsw.edu.au
x.cooney@unsw.edu.au
print_diary.c
// Write a C program, print_diary.c, which prints the contents
// of the file $HOME/.diary to stdout
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// path = <whatever the HOME env variable is>/.diary
int main(void) {
char *home = getenv("HOME");
printf("home = \"%s\"\n", home);
char *diary_suffix = "/.diary";
int path_size = strlen(home) + strlen(diary_suffix) + 1;
char *path = malloc(path_size);
if (path == NULL) {
perror("malloc");
return 1;
}
snprintf(path, path_size, "%s%s", home, diary_suffix);
printf("path = \"%s\"\n", path);
FILE *stream = fopen(path, "r");
int byte;
while ((byte = fgetc(stream)) != EOF) {
putchar(byte);
}
fclose(stream);
free(path);
}
chmod_if_public_write.c
#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>
// ./chmod_if_public_write print_diary.c file code.txt
void chmod_if_public_write(char *path);
int main(int argc, char *argv[]) {
for (int i = 1; i < argc; i++) {
chmod_if_public_write(argv[i]);
}
}
void chmod_if_public_write(char *path) {
struct stat statbuf;
if (stat(path, &statbuf) != 0) {
perror(path);
return;
}
if ((statbuf.st_mode & S_IWOTH) == 0) {
printf("public write bit not set for %s\n", path);
return;
}
printf("public write bit set for %s... chmoding!\n", path);
// ~S_IWOTH = 111111101
mode_t new_permission = statbuf.st_mode & ~S_IWOTH;
if (chmod(path, new_permission) != 0) {
perror(path);
}
}
first_line.c
// Write a C program, first_line.c, which is given one command-line argument,
// the name of a file, and which prints the first line of that file to stdout.
// If given an incorrect number of arguments, or if there was an error opening
// the file, it should print a suitable error message.
#include <stdio.h>
#include <stdlib.h>
// $ ./first_line lines.txt
// argc = 2
// argv[0] = "./first_line"
// argv[1] = "lines.txt"
int main(int argc, char *argv[]) {
if (argc != 2) {
fprintf(stderr, "Usage: ./first_line <file>\n");
exit(1);
}
char *path = argv[1];
FILE *stream = fopen(path, "r");
if (stream == NULL) {
perror(path);
exit(1);
}
// functions to read from a file: fgetc, fread, fscanf, fgets
// functions to write from a file: fputc, fwrite, fprintf, fputs
int byte;
while ((byte = fgetc(stream)) != EOF) {
putchar(byte);
if (byte == '\n') {
break;
}
}
fclose(stream);
}
float_weird.c
#include <stdio.h>
int main(void) {
float a = 0.1;
float b = 0.2;
float sum = a + b;
printf("a = %.9g, b = %.9g and sum = %.9g\n", a, b, sum);
printf("And sum == 0.3 is: %d\n", sum == 0.3);
}
get_bit_groups.c
#include <stdint.h>
#include <stdio.h>
typedef struct six_bit_groups {
uint8_t middle_bits;
uint8_t lower_bits;
} six_bit_groups_t;
/*
Example:
01100010 10101101 11001100 10010011
^^^ ^^^ ^^^^^^
middle lower
= 46 = 19
01100010 10101101 11001100 10010011 <-- value
00000000 00000000 0000000 00111111 <-- mask
00000000 00000000 0000000 01000000 <-- 1 << 6
-----------------------------------------
00000000 00000000 0000000 00010011 <-- value & mask
00000000 00000000 0000000 00111111 <-- mask
00000000 00000111 1110000 00000000 <-- mask << 13
00000000 00000101 1100000 00000000 <-- value & mask
00000000 00000101 1100000 00000000 <-- (value & mask) >> 13
*/
six_bit_groups_t get_bit_groups(uint32_t value) {
// uint32_t mask = 0b111111;
uint32_t mask = 0x3f;
// uint32_t mask = 077;
// uint32_t mask = 63;
// uint32_t mask = (1 << n) - 1;
// uint32_t lower_bits = mask & value;
// // uint32_t middle_bits = ((mask << 13) & value) >> 13;
// uint32_t middle_bits = (value >> 13) & mask;
int a = 30000;
int b = 30000;
int result = a + b;
six_bit_groups_t result;
result.lower_bits = lower_bits;
result.middle_bits = middle_bits;
return result;
}
reverse_bits.c
#include <assert.h>
#include <stdio.h>
#include <stdint.h>
// Reverse a 32 bit value
uint32_t reverse_bits(uint32_t value) {
uint32_t answer = 0;
for (int i = 0; i < 32; i++) {
// 1. first check if bit `i` in `value` is a 1?
uint32_t mask = 1;
mask = mask << i;
if ((value & mask) != 0) {
// 2. => if so, set opposite bit to `i` in answer
int opposite_bit_index = 31 - i;
mask = 1;
mask <<= opposite_bit_index;
answer = answer | mask;
}
}
return answer;
}
int main(void) {
assert(reverse_bits(0xFFFFFFFF) == 0xFFFFFFFF);
assert(reverse_bits(0x00000000) == 0x00000000);
assert(reverse_bits(0x1) == 0x80000000);
assert(reverse_bits(0x2) == 0x40000000);
assert(reverse_bits(0x01234567) == 0xE6A2C480);
printf("All tests passed!\n");
return 0;
}
examples.txt
uint16_t a = 0x5566, b = 0xAAAA, c = 0x0001;
a) a | b
b) a & b
c) a ^ b
d) a & ~b
e) c << 6
f) a >> 4
g) a & (b << 1)
h) b | c
i) a & ~c
No code yet! If the tutorial is over, please remind Xavier to run the upload script :)
print_array.c
// A simple program that will print 10 numbers from an array
#define N_SIZE 10
#include <stdio.h>
// int -> word
// char -> byte
// short -> half
int numbers[N_SIZE] = {
3, 1, 4, 1, 5, 9, 2, 6, 5, 3
};
int main(void) {
for (int i = 0; i < N_SIZE; i++) {
int num = numbers[i];
printf("%d\n", num);
}
}
print_array.s
MY_FAVOURITE_NUMBER = 10
main:
# Locals:
# i: $t0
# num: $t1
loop_init:
# int i = 0;
li $t0, 0
loop_cond:
bge $t0, MY_FAVOURITE_NUMBER, loop_end
loop_body:
# int num = numbers[i];
# 1. get the address of the object
# we're accessing into a register
# &numbers[i] = &numbers + sizeof(element) * i
la $t2, numbers # &numbers
mul $t3, 4, $t0 # i * 4
add $t2, numbers, $t3 # &numbers + i * 4
# == &numbers[i]
# 2. figure out if we're doing a load
# or a store
# it's a load!
# 3. figure out if we're loading/storing
# a byte, half or word
# we're loading a word
lw $t1, ($t2)
# printf("%d\n", num);
li $v0, 1
move $a0, $t1
syscall
li $v0, 11
li $a0, '\n'
syscall
loop_step:
addi $t0, $t0, 1
b loop_cond
loop_end:
li $v0, 0
jr $ra
.data
numbers:
.word 3, 1, 4, 1, 5, 9, 2, 6, 5, 3
read_array.c
// A simple program that will read 10 numbers into an array
#define N_SIZE 5
#include <stdio.h>
int numbers[N_SIZE];
int main(void) {
int i;
i = 0;
while (i < N_SIZE) {
scanf("%d", &numbers[i]);
i++;
}
i = 0;
while (i < N_SIZE) {
int num = numbers[i];
printf("%d\n", num);
i++;
}
}
read_array.s
N_SIZE = 5
SIZEOF_INT = 4
main:
# Locals:
# i: $t0
# num: $t1
read_loop_init:
li $t0, 0
read_loop_cond:
bge $t0, N_SIZE, read_loop_end
read_loop_body:
# scanf("%d", &numbers[i]);
# numbers[i] = read_int()
li $v0, 5
syscall
# 1. get address
la $t2, numbers # &numbers
mul $t3, 4, $t0 # i * 4
add $t2, numbers, $t3 # &numbers + i * 4
# == &numbers[i]
# 2. it's a store!
# 3. word
sw $v0, ($t2)
read_loop_step:
addi $t0, $t0, 1
b read_loop_cond
read_loop_end:
print_loop_init:
# int i = 0;
li $t0, 0
print_loop_cond:
bge $t0, N_SIZE, print_loop_end
print_loop_body:
# int num = numbers[i];
# 1. get the address of the object
# we're accessing into a register
# &numbers[i] = &numbers + sizeof(element) * i
la $t2, numbers # &numbers
mul $t3, 4, $t0 # i * 4
add $t2, numbers, $t3 # &numbers + i * 4
# == &numbers[i]
# 2. figure out if we're doing a load
# or a store
# it's a load!
# 3. figure out if we're loading/storing
# a byte, half or word
# we're loading a word
lw $t1, ($t2)
# printf("%d\n", num);
li $v0, 1
move $a0, $t1
syscall
li $v0, 11
li $a0, '\n'
syscall
print_loop_step:
addi $t0, $t0, 1
b print_loop_cond
print_loop_end:
li $v0, 0
jr $ra
.data
.align 2
numbers:
.space SIZEOF_INT*N_SIZE
# .word 0:N_SIZE
# .word 3, 1, 4, 1, 5, 9, 2, 6, 5, 3
hello.s
# Write a MIPS assembly program that prints "Hello, world!"
.text
main:
li $v0, 4 # $v0 = 4
la $a0, hello_world_str
syscall # printf("Hello, world!")
li $v0, 0
jr $ra # return 0;
.data
hello_world_str:
.asciiz "Hello, world!\n"
square.c
// Prints the square of a number
#include <stdio.h>
int main(void) {
int x, y;
printf("Enter a number: ");
scanf("%d", &x);
// printf("%d\n", x * x);
y = x * x;
printf("%d", y);
putchar('\n');
}
square.s
main:
# Locals:
# x: $t0
# y: $t1
# int x;
# printf("Enter a number: ");
li $v0, 4
la $a0, enter_a_number_str
syscall
# scanf("%d", &x);
li $v0, 5
syscall
move $t0, $v0 # $t0 = $v0
# y = x * x;
mul $t1, $t0, $t0
# printf("%d", y);
li $v0, 1
move $a0, $t1
syscall
# putchar('\n');
li $v0, 11
li $a0, '\n'
syscall
# return 0;
li $v0, 0
jr $ra
.data
enter_a_number_str:
.asciiz "Enter a number: "
bounded_square.c
// Squares a number, unless its square is too big for a 32-bit integer.
// If it is too big, prints an error message instead.
#include <stdio.h>
#define SQUARE_MAX 46340
int main(void) {
int x, y;
printf("Enter a number: ");
scanf("%d", &x);
// if (x > SQUARE_MAX) {
// if (x <= SQUARE_MAX) { goto print_square; }
if (x > SQUARE_MAX) { goto square_too_big; }
goto print_square;
square_too_big:
printf("square too big for 32 bits\n");
goto epilogue;
// } else {
print_square:
y = x * x;
printf("%d\n", y);
// }
epilogue:
return 0;
}
bounded_square.s
SQUARE_MAX = 46340
main:
# Locals:
# x: $t0
# y: $t1
# int x;
# printf("Enter a number: ");
li $v0, 4
la $a0, enter_a_number_str
syscall
# scanf("%d", &x);
li $v0, 5
syscall
move $t0, $v0 # $t0 = $v0
ble $t0, SQUARE_MAX, print_square
# printf("square too big for 32 bits\n");
li $v0, 4
la $a0, square_too_big_str
syscall
b epilogue
print_square:
# y = x * x;
mul $t1, $t0, $t0
# printf("%d", y);
li $v0, 1
move $a0, $t1
syscall
# putchar('\n');
li $v0, 11
li $a0, '\n'
syscall
epilogue:
# return 0;
li $v0, 0
jr $ra
.data
enter_a_number_str:
.asciiz "Enter a number: "
square_too_big_str:
.asciiz "square too big for 32 bits\n"
for.c
// Print every third number from 24 to 42.
#include <stdio.h>
int main(void) {
// for (int x = 24; x < 42; x += 3) {
// printf("%d\n", x);
// }
int x = 24;
loop_cond:
if (x >= 42) { goto loop_end; }
printf("%d\n", x);
x += 3;
goto loop_cond;
loop_end:;
}
No code yet! If the tutorial is over, please remind Xavier to run the upload script :)