CPSC 355: Tutorial 12
Structs
PhD Student
Fall 2017
Outline
Today we'll cover one large example that will include everything you need for assignment 4.
Assignment 4
#include <stdio.h>
#define FALSE 0
#define TRUE 1
struct point {
int x,y;
};
struct dimension {
int width, length;
};
struct pyramid {
struct point origin;
struct dimension base;
int height;
int volume;
};
struct pyramid newPyramid(){
struct pyramid p;
p.origin.x = 0;
p.origin.y = 0;
p.base.width = 2;
p.base.length = 2;
p.height = 3;
p.volume = (p.base.width * p.base.length * p.height)/3.;
return p;
}
Assignment 4
void move(struct pyramid *p, int deltaX, int deltaY)
{
p->origin.x += deltaX;
p->origin.y += deltaY;
}
void scale(struct pyramid *p, int factor)
{
p->base.width *= factor;
p->base.length *= factor;
p->height *= factor;
p->volume *= (p->base.width * p->base.length * p->height)/3;
}
void printPyramid(char *name, struct pyramid *p)
{
printf("Pyramid %s origin: (%d, %d)\n", name, p->origin.x, p->origin.y);
printf("\tBase width=%d Base length = %d\n", p->base.width, p->base.length);
printf("\tHeight = %d\n", p->height);
printf("\tVolume = %d\n", p->volume);
}
int equalSize(struct pyramid *p1, struct pyramid *p2)
{
int result = FALSE;
if(p1->base.width == p2->base.width) {
if(p1->base.length == p2->base.length) {
if(p1->height == p2->height) {
result = TRUE;
}
}
}
return result;
}
Assignment 4
int main()
{
struct pyramid first, second;
first = newPyramid();
second = newPyramid();
printf("Initial pyramid values:\n");
printPyramid("first", &first);
printPyramid("second", &second);
if(equalSize(&first, &second)){
move(&first, -5, 7);
scale(&second, 3);
}
printf("\nChanged pyramid values:\n");
printPyramid("first", &first);
printPyramid("second", &second);
}
Example
#include <stdio.h>
struct physique {
int height;
int age;
};
struct student {
unsigned long id;
struct physique b;
};
struct student newStudent(unsigned long id){
struct student s;
s.id = id;
s.b.age = -1; // -1 means unknown
s.b.height = -1; // -1 means unknown
return s;
}
void printStudent(struct student *s) {
printf("Student: %ld\n",s->id);
if(s->b.age > 0)
printf("\tAge:%d\n",s->bod.age);
else
printf("\tAge unknown!");
}
Example
...
void studentBirthday(struct student *s) {
if(s->b.age > 0)
s->b.age += 1;
}
void main(int argc, char *argv) {
struct student s = newStudent(30100000);
printStudent(&s);
s.b.age = 22;
printStudent(&s);
studentBirthday(&s);
printStudent(&s);
}
Structs
struct physique {
int height;
int age;
};
struct student {
unsigned long id;
struct physique b;
};
In memory
struct student |
---|
id_number (8 bytes) |
height (4 bytes) |
age (4 bytes) |
Structs are like objects in higher level languages, but they only model objects, they have no methods.
Structs
struct physique {
int height;
int age;
};
struct student {
unsigned long id;
struct physique b;
};
void main() {
struct student s;
s.id = 30100000;
s.b.age = 22;
s.b.height = 180;
}
Structs are like objects in higher level languages, but they only model objects, they have no methods.
Structs
// Offsets from the start of the physique struct
phys_height = 0 // offset 0, size = 4 bytes
phys_age = 4 // offset 4, size = 4 bytes
phys_struct_size = 8 // total 8 bytes
// Offsets from the start of the student struct
student_id = 0 // offset 0 from start, size 8 (unsigned long)
student_b = 8 // offset 8, size = 8 (phys_struct_size)
student_struct_size = 16 // total size
fp .req x29
lr .req x30
alloc = -(16 + student_struct_size) & -16
dealloc = -alloc
s_fo = 16 // offset to s variable on the stack (via frame pointer)
.balign 4
.global main
main:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
ldr x0, =30100000 // x0 = 30100000 (64 bit)
str x0, [fp, s_fo + student_id] // Store in s.id
mov w0, 22 // w0 = 22 (32 bit)
str w0, [fp, s_fo + student_b + phys_age] // s.b.age = 22
mov w0, 180 // w0 = 180 (32 bit)
str w0, [fp, s_fo + student_b + phys_height] // s.b.height = 22
ldp fp, lr, [sp], dealloc
ret
Structs
struct physique { ... };
struct student { ... };
struct student newStudent(unsigned long id){
struct student s;
s.id = id;
s.b.age = -1;
s.b.height = -1;
return s;
}
void main() {
struct student s;
s = newStudent(3010000);
}
Structs are like objects in higher level languages, but they only model objects, they have no methods. Here's a constructor like function for a student.
In newStudent(), a student struct is created, assigned values, then copied out in the return
// Offsets from the start of the physique struct
phys_height = 0 // offset 0, size = 4 bytes
phys_age = 4 // offset 4, size = 4 bytes
phys_struct_size = 8 // total 8 bytes
// Offsets from the start of the student struct
student_id = 0 // offset 0 from start, size 8 (unsigned long)
student_b = 8 // offset 8, size = 8 (phys_struct_size)
student_struct_size = 16 // total size
fp .req x29
lr .req x30
alloc = -(16 + student_struct_size) & -16
dealloc = -alloc
s_fo = 16 // offset to s variable on the stack (via frame pointer)
.balign 4
// Creates a new student struct
newStudent:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
str x0, [fp, s_fo + student_id] // Store arg 0 in s.id
mov w0, -1 // w0 = -1 (32 bit)
str w0, [fp, s_fo + student_b + phys_age] // s.b.age = -1
str w0, [fp, s_fo + student_b + phys_height] // s.b.height = -1
// By convention, the above operations HAD to be done on the local stack
// We now copy this out to the return struct (x8 points to the ret struct)
// You need to copy ALL the struct elements
ldr x9, [fp, s_fo + student_id] // copy s.id
str x9, [x8, student_id] // We don't add s_fo, because the address
// of the destination is not on the stack
ldr w9, [fp, s_fo + student_b + phys_age] // copy s.b.age
str w9, [x8, student_b + phys_age]
ldr w9, [fp, s_fo + student_b + phys_height] // copy s.b.height
str w9, [x8, student_b + phys_height]
ldp fp, lr, [sp], dealloc
ret
// redefine alloc for main
alloc = -(16 + student_struct_size) & -16
dealloc = -alloc
s_fo = 16 // offset to s variable on the stack (via frame pointer)
.global main
main:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
// Set x8 to the address of the student struct on the stack
add x8, fp, s_fo
ldr x0, =3010000
bl newStudent
// s_fo now contains the new student
ldp fp, lr, [sp], dealloc
ret
Structs
struct physique { ... };
struct student { ... };
struct student newStudent(unsigned long id){ ... }
void printStudent(struct student *s) {
printf("Student: %ld\n",s->id);
if(s->b.age >= 0)
printf("\tAge:%d\n",s->b.age);
else
printf("\tAge unknown!\n");
}
void main() {
struct student s;
s = newStudent(3010000);
printStudent(&s);
}
Passing by reference. *s is a pointer to a location in memory. &s gets the address of a variable on the stack
// Offsets from the start of the physique struct
phys_height = 0 // offset 0, size = 4 bytes
phys_age = 4 // offset 4, size = 4 bytes
phys_struct_size = 8 // total 8 bytes
// Offsets from the start of the student struct
student_id = 0 // offset 0 from start, size 8 (unsigned long)
student_b = 8 // offset 8, size = 8 (phys_struct_size)
student_struct_size = 16 // total size
fp .req x29
lr .req x30
//..
// newStudent code goes here
//..
printStudent:
stp fp, lr, [sp, -32]! // We have no stack variables, but we'll be using
// x19, so we need to allocate space to save x19
mov fp, sp
str x19, [fp, 16] // store x19 on the stack. The function that called
// this function might depend on x19 being preserved
// so we must save it
// x0 contains the pointer to a student struct, so lets save that in
// x19, a register we know won't get clobbered
mov x19, x0
ldr x0, =fmt1
ldr x1, [x19, student_id] // load s->id
bl printf
ldr w0, [x19, student_b + phys_age] // load s->b.age
cmp w0, 0
b.lt else1 // go to else case if age < 0
mov w1, w0 // w0 had age in it, so move it to w1 (arg 1)
ldr x0, =fmt2 // load arg 0 as fmt2
bl printf // print
b return_ps // return
else1:
ldr x0, =fmt3
bl printf
return_ps:
ldr x19, [fp, 16]
ldp fp, lr, [sp], 32
ret
main:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
// Set x8 to the address of the student struct on the stack
add x8, fp, s_fo
ldr x0, =30100000
bl newStudent
// s_fo now contains the new student
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent
ldp fp, lr, [sp], dealloc
ret
Structs
struct physique { ... };
struct student { ... };
struct student newStudent(unsigned long id){ ... }
void printStudent(struct student *s) { ... }
void studentBirthday(struct student *s) {
if(s->b.age > 0)
s->b.age += 1;
}
void main(int argc, char *argv) {
struct student s = newStudent(30100000);
printStudent(&s);
s.b.age = 22;
printStudent(&s);
studentBirthday(&s);
printStudent(&s);
}
Passing by reference. *s is a pointer to a location in memory. &s gets the address of a variable on the stack
// Offsets from the start of the physique struct
phys_height = 0 // offset 0, size = 4 bytes
phys_age = 4 // offset 4, size = 4 bytes
phys_struct_size = 8 // total 8 bytes
// Offsets from the start of the student struct
student_id = 0 // offset 0 from start, size 8 (unsigned long)
student_b = 8 // offset 8, size = 8 (phys_struct_size)
student_struct_size = 16 // total size
fp .req x29
lr .req x30
//..
// newStudent code goes here
// printStudent code goes here
//..
studentBirthday:
stp fp, lr, [sp, -16]! // We don't need to save anything other than fp and lr
mov fp, sp
// x0 is the address of the struct s
ldr w9, [x0, student_b + phys_age] // load s->b.age
cmp w9, 0
b.lt return_sb // if age < 0, return
add w9, w9, 1 // add one to the age
str w9, [x0, student_b + phys_age] // and store it
return_sb:
ldp fp, lr, [sp], 16 // restore fp, lr
ret // return
main:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
// Set x8 to the address of the student struct on the stack
add x8, fp, s_fo
ldr x0, =30100000
bl newStudent
// s_fo now contains the new student
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent
mov x2, 22
str x2, [fp, s_fo + student_b + phys_age] // s.b.age = 22
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl studentBirthday
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent
ldp fp, lr, [sp], dealloc
ret
// File: ex1.asm
// Author: Joshua Horacsek
// Date: November 6th 2017
//
// Description:
// A simple example showing how to pass around structs.
// Setup some macros for ourselves to make our lives easier
// Offsets from the start of the physique struct
phys_height = 0 // offset 0, size = 4 bytes
phys_age = 4 // offset 4, size = 4 bytes
phys_struct_size = 8 // total 8 bytes
// Offsets from the start of the student struct
student_id = 0 // offset 0 from start, size 8 (unsigned long)
student_b = 8 // offset 8, size = 8 (phys_struct_size)
student_struct_size = 16 // total size
fp .req x29
lr .req x30
alloc = -(16 + student_struct_size) & -16
dealloc = -alloc
s_fo = 16 // offset to s variable on the stack (via frame pointer)
// format strings
fmt1: .string "Student: %ld\n"
fmt2: .string "\tAge:%d\n"
fmt3: .string "\tAge unknown!\n"
Completed Example
.balign 4
///////////////////////////////////////////
// function: newStudent
///////////////////////////////////////////
alloc = -(16 + student_struct_size) & -16
dealloc = -alloc
s_fo = 16 // offset to s variable on the stack (via frame pointer)
newStudent:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
str x0, [fp, s_fo + student_id] // Store arg 0 in s.id
mov w0, -1 // w0 = -1 (32 bit)
str w0, [fp, s_fo + student_b + phys_age] // s.b.age = -1
str w0, [fp, s_fo + student_b + phys_height] // s.b.height = -1
// By convention, the above operations HAD to be done on the local stack
// We now copy this out to the return struct (x8 points to the ret struct)
// You need to copy ALL the struct elements
ldr x9, [fp, s_fo + student_id] // copy s.id
str x9, [x8, student_id] // We don't add s_fo, because the address
// of the destination is not on the stack
ldr w9, [fp, s_fo + student_b + phys_age] // copy s.b.age
str w9, [x8, student_b + phys_age]
ldr w9, [fp, s_fo + student_b + phys_height] // copy s.b.height
str w9, [x8, student_b + phys_height]
ldp fp, lr, [sp], dealloc
ret
///////////////////////////////////////////
// function: printStudent
///////////////////////////////////////////
alloc = -32 // We have no stack vars, but we need to keep x19
dealloc = -alloc
printStudent:
stp fp, lr, [sp, alloc]!
mov fp, sp
str x19, [fp, 16] // store x19 on the stack. The function that called
// this function might depend on x19 being preserved
// so we must save it
// x0 contains the pointer to a student struct, so lets save that in
// x19, a register we know won't get clobbered
mov x19, x0 // save x0 into x19
ldr x0, =fmt1 // arg0 = fmt1
ldr x1, [x19, student_id] // arg1 = s->id
bl printf // printf(fmt1, s->id);
// load age into w0
ldr w0, [x19, student_b + phys_age]
cmp w0, 0 // compare age with 0
b.lt else1 // go to else case if age < 0
mov w1, w0 // w0 had age in it, so move it to w1 (arg 1)
ldr x0, =fmt2 // load arg 0 as fmt2
bl printf // print
b return_ps // return
else1:
ldr x0, =fmt3 // just print unknown age
bl printf
return_ps:
ldr x19, [fp, 16] // restore x19
ldp fp, lr, [sp], dealloc
ret
///////////////////////////////////////////
// function: studentBirthday
///////////////////////////////////////////
studentBirthday:
stp fp, lr, [sp, -16]! // We don't need to save anything other than fp and lr
mov fp, sp
// x0 is the address of the struct s
ldr w9, [x0, student_b + phys_age] // load s->b.age
cmp w9, 0
b.lt return_sb // if age < 0, return
add w9, w9, 1 // add one to the age
str w9, [x0, student_b + phys_age] // and store it
return_sb:
ldp fp, lr, [sp], 16 // restore fp, lr
ret // return
///////////////////////////////////////////
// function: main
///////////////////////////////////////////
alloc = -(16 + student_struct_size) & -16
dealloc = -alloc
s_fo = 16 // offset to s variable on the stack (via frame pointer)
.global main
main:
stp fp, lr, [sp, alloc]! // Allocate enough stack space for s struct variable
mov fp, sp
// Set x8 to the address of the student struct on the stack
add x8, fp, s_fo
ldr x0, =30100000
bl newStudent
// s_fo now contains the new student
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent
// set the student's age
mov x2, 22
str x2, [fp, s_fo + student_b + phys_age] // s.b.age = 22
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent // printStudent(&s);
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl studentBirthday // studentBirthday(&s);
add x0, fp, s_fo // x0 = &s = address of s variable on stack
bl printStudent // printStudent(&s);
ldp fp, lr, [sp], dealloc
ret
struct wheel {
int width, radius;
};
struct body {
int width, length, depth;
};
struct car {
struct body b;
struct wheel w1;
struct wheel w2;
struct wheel w3;
struct wheel w4;
int doors;
};
Multiple Nested Structs
// Offsets from the start of the physique struct
wheel_width = 0 // offset 0, size = 4 bytes
wheel_radius = 4 // offset 4, size = 4 bytes
wheel_struct_size = 8 // total 8 bytes
// Offsets from the start of the physique struct
body_width = 0 // offset 0, size = 4 bytes
body_length = 4 // offset 4, size = 4 bytes
body_depth = 8 // offset 8, size = 4 bytes
body_struct_size = 12 // total 12 bytes
// Offsets from the start of the student struct
car_b = 0 // offset 0 from start, size 12 (body_struct_size)
car_w1 = 12 // offset 12, size = 8 (wheel_struct_size)
car_w2 = 20 // offset 20, size = 8 (wheel_struct_size)
car_w3 = 28 // offset 28, size = 8 (wheel_struct_size)
car_w4 = 36 // offset 36, size = 8 (wheel_struct_size)
car_doors = 40 // offset 40, size = 4 (integer)
car_struct_size = 44 // total size
Next Day
Work day
CPSC 355: Tutorial 12
By Joshua Horacsek
CPSC 355: Tutorial 12
- 2,453