From 215c1849f16a558c9017af19891024fcf561280f Mon Sep 17 00:00:00 2001 From: Riyyi Date: Wed, 27 Aug 2025 22:08:26 +0200 Subject: [PATCH] Improve CMake structure --- CMakeLists.txt | 7 +-- src/{4-1 => 4-1-enums}/color.h | 0 src/4-1-enums/main.c | 28 ++++++++++ src/4-1/main.c | 27 ---------- src/{4-2 => 4-2-non-default-values}/color.h | 0 src/4-2-non-default-values/main.c | 28 ++++++++++ src/4-2/main.c | 27 ---------- src/4-3-switch-case/http.c | 27 ++++++++++ src/{4-3 => 4-3-switch-case}/http.h | 0 src/4-3-switch-case/main.c | 28 ++++++++++ src/4-3/http.c | 7 --- src/4-3/main.c | 27 ---------- src/4-4-sizeof-enum/main.c | 23 +++++++++ src/5-1-union/exercise.c | 34 ++++++++++++ src/5-1-union/exercise.h | 20 ++++++++ src/5-1-union/main.c | 51 ++++++++++++++++++ src/5-2-memory-layout/main.c | 24 +++++++++ src/5-3-5-4-union-size/main.c | 42 +++++++++++++++ src/5-5-helper-fields/exercise.h | 10 ++++ src/5-5-helper-fields/main.c | 53 +++++++++++++++++++ src/6-1-the-stack/exercise.h | 4 ++ src/6-1-the-stack/main.c | 48 +++++++++++++++++ src/6-2-why-a-stack/main.c | 9 ++++ src/6-3-stack-overflow/main.c | 16 ++++++ src/6-4-pointers-to-the-stack/main.c | 25 +++++++++ src/6-5-the-heap/exercise.c | 10 ++++ src/6-5-the-heap/exercise.h | 1 + src/6-5-the-heap/main.c | 44 ++++++++++++++++ src/munit.h | 57 +++++++++++++++++++++ 29 files changed, 584 insertions(+), 93 deletions(-) rename src/{4-1 => 4-1-enums}/color.h (100%) create mode 100644 src/4-1-enums/main.c delete mode 100644 src/4-1/main.c rename src/{4-2 => 4-2-non-default-values}/color.h (100%) create mode 100644 src/4-2-non-default-values/main.c delete mode 100644 src/4-2/main.c create mode 100644 src/4-3-switch-case/http.c rename src/{4-3 => 4-3-switch-case}/http.h (100%) create mode 100644 src/4-3-switch-case/main.c delete mode 100644 src/4-3/http.c delete mode 100644 src/4-3/main.c create mode 100644 src/4-4-sizeof-enum/main.c create mode 100644 src/5-1-union/exercise.c create mode 100644 src/5-1-union/exercise.h create mode 100644 src/5-1-union/main.c create mode 100644 src/5-2-memory-layout/main.c create mode 100644 src/5-3-5-4-union-size/main.c create mode 100644 src/5-5-helper-fields/exercise.h create mode 100644 src/5-5-helper-fields/main.c create mode 100644 src/6-1-the-stack/exercise.h create mode 100644 src/6-1-the-stack/main.c create mode 100644 src/6-2-why-a-stack/main.c create mode 100644 src/6-3-stack-overflow/main.c create mode 100644 src/6-4-pointers-to-the-stack/main.c create mode 100644 src/6-5-the-heap/exercise.c create mode 100644 src/6-5-the-heap/exercise.h create mode 100644 src/6-5-the-heap/main.c create mode 100644 src/munit.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b6f6da2..3893920 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,9 +17,6 @@ file(GLOB_RECURSE LIBRARY_SOURCES "vendor/munit/*.c") add_library(munit ${LIBRARY_SOURCES}) -target_include_directories(munit PUBLIC - "vendor/munit") - # ------------------------------------------ # Executable @@ -42,8 +39,8 @@ foreach(LESSON ${LESSONS}) add_executable(${EXE_NAME} ${LESSON_SOURCES}) target_include_directories(${EXE_NAME} PRIVATE - ${CMAKE_CURRENT_SOURCE_DIR}/${LESSON} - "vendor/munit") + ${CMAKE_CURRENT_SOURCE_DIR}/src + ${CMAKE_CURRENT_SOURCE_DIR}/${LESSON}) target_link_libraries(${EXE_NAME} munit) # Collect all the directory names for the run target diff --git a/src/4-1/color.h b/src/4-1-enums/color.h similarity index 100% rename from src/4-1/color.h rename to src/4-1-enums/color.h diff --git a/src/4-1-enums/main.c b/src/4-1-enums/main.c new file mode 100644 index 0000000..49e93d3 --- /dev/null +++ b/src/4-1-enums/main.c @@ -0,0 +1,28 @@ +#include "munit.h" + +#include "color.h" + +munit_case(RUN, test_color_enum1, { + assert_int(RED, ==, 0, "RED is defined as 0"); + assert_int(GREEN, ==, 1, "GREEN is defined as 1"); + assert_int(BLUE, ==, 2, "BLUE is defined as 2"); +}); + +munit_case(SUBMIT, test_color_enum2, { + assert_int(RED, !=, 4, "RED is not defined as 4"); + assert_int(GREEN, !=, 2, "GREEN is not defined as 2"); + assert_int(BLUE, !=, 0, "BLUE is not defined as 0"); +}); + +int main() +{ + MunitTest tests[] = { + munit_test("/are_defined", test_color_enum1), + munit_test("/are_defined_correctly", test_color_enum2), + munit_null_test, + }; + + MunitSuite suite = munit_suite("colors", tests); + + return munit_suite_main(&suite, NULL, 0, NULL); +} diff --git a/src/4-1/main.c b/src/4-1/main.c deleted file mode 100644 index 4859406..0000000 --- a/src/4-1/main.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "munit.h" - -#include "color.h" - -munit_case(RUN, test_color_enum1, { - assert_int(RED, ==, 0, "RED is defined as 0"); - assert_int(GREEN, ==, 1, "GREEN is defined as 1"); - assert_int(BLUE, ==, 2, "BLUE is defined as 2"); -}); - -munit_case(SUBMIT, test_color_enum2, { - assert_int(RED, !=, 4, "RED is not defined as 4"); - assert_int(GREEN, !=, 2, "GREEN is not defined as 2"); - assert_int(BLUE, !=, 0, "BLUE is not defined as 0"); -}); - -int main() { - MunitTest tests[] = { - munit_test("/are_defined", test_color_enum1), - munit_test("/are_defined_correctly", test_color_enum2), - munit_null_test, - }; - - MunitSuite suite = munit_suite("colors", tests); - - return munit_suite_main(&suite, NULL, 0, NULL); -} diff --git a/src/4-2/color.h b/src/4-2-non-default-values/color.h similarity index 100% rename from src/4-2/color.h rename to src/4-2-non-default-values/color.h diff --git a/src/4-2-non-default-values/main.c b/src/4-2-non-default-values/main.c new file mode 100644 index 0000000..cf4fb46 --- /dev/null +++ b/src/4-2-non-default-values/main.c @@ -0,0 +1,28 @@ +#include "munit.h" + +#include "color.h" + +munit_case(RUN, test_colors_defined, { + assert_int(RED, ==, 55, "RED is defined as 55 (nvim green!)"); + assert_int(GREEN, ==, 176, "GREEN is defined as 176 (nvim green!)"); + assert_int(BLUE, ==, 38, "BLUE is defined as 38 (nvim green!)"); +}); + +munit_case(SUBMIT, test_colors_defined_correctly, { + assert_int(RED, !=, 0, "RED is not defined as 0 (vsc*de blue!)"); + assert_int(GREEN, !=, 120, "GREEN is not defined as 120 (vsc*de blue!)"); + assert_int(BLUE, !=, 215, "BLUE is not defined as 215 (vsc*de blue!)"); +}); + +int main() +{ + MunitTest tests[] = { + munit_test("/defined", test_colors_defined), + munit_test("/defined_vscode", test_colors_defined_correctly), + munit_null_test, + }; + + MunitSuite suite = munit_suite("colors", tests); + + return munit_suite_main(&suite, NULL, 0, NULL); +} diff --git a/src/4-2/main.c b/src/4-2/main.c deleted file mode 100644 index e4d8432..0000000 --- a/src/4-2/main.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "munit.h" - -#include "color.h" - -munit_case(RUN, test_colors_defined, { - assert_int(RED, ==, 55, "RED is defined as 55 (nvim green!)"); - assert_int(GREEN, ==, 176, "GREEN is defined as 176 (nvim green!)"); - assert_int(BLUE, ==, 38, "BLUE is defined as 38 (nvim green!)"); -}); - -munit_case(SUBMIT, test_colors_defined_correctly, { - assert_int(RED, !=, 0, "RED is not defined as 0 (vsc*de blue!)"); - assert_int(GREEN, !=, 120, "GREEN is not defined as 120 (vsc*de blue!)"); - assert_int(BLUE, !=, 215, "BLUE is not defined as 215 (vsc*de blue!)"); -}); - -int main() { - MunitTest tests[] = { - munit_test("/defined", test_colors_defined), - munit_test("/defined_vscode", test_colors_defined_correctly), - munit_null_test, - }; - - MunitSuite suite = munit_suite("colors", tests); - - return munit_suite_main(&suite, NULL, 0, NULL); -} diff --git a/src/4-3-switch-case/http.c b/src/4-3-switch-case/http.c new file mode 100644 index 0000000..58073c3 --- /dev/null +++ b/src/4-3-switch-case/http.c @@ -0,0 +1,27 @@ +#include "http.h" + +char* http_to_str(http_error_code_t code) +{ + switch (code) { + case HTTP_BAD_REQUEST: + return "400 Bad Request"; + break; + case HTTP_UNAUTHORIZED: + return "401 Unauthorized"; + break; + case HTTP_NOT_FOUND: + return "404 Not Found"; + break; + case HTTP_TEAPOT: + return "418 I AM A TEAPOT!"; + break; + case HTTP_INTERNAL_SERVER_ERROR: + return "500 Internal Server Error"; + break; + default: + return "Unknown HTTP status code"; + break; + }; + + return 0; +} diff --git a/src/4-3/http.h b/src/4-3-switch-case/http.h similarity index 100% rename from src/4-3/http.h rename to src/4-3-switch-case/http.h diff --git a/src/4-3-switch-case/main.c b/src/4-3-switch-case/main.c new file mode 100644 index 0000000..81625f5 --- /dev/null +++ b/src/4-3-switch-case/main.c @@ -0,0 +1,28 @@ +#include "munit.h" + +#include "http.h" + +munit_case(RUN, test_switch_enum, { + assert_string_equal(http_to_str(HTTP_BAD_REQUEST), "400 Bad Request", ""); + assert_string_equal(http_to_str(HTTP_UNAUTHORIZED), "401 Unauthorized", ""); + assert_string_equal(http_to_str(HTTP_NOT_FOUND), "404 Not Found", ""); + assert_string_equal(http_to_str(HTTP_TEAPOT), "418 I AM A TEAPOT!", ""); + assert_string_equal(http_to_str(HTTP_INTERNAL_SERVER_ERROR), "500 Internal Server Error", ""); +}); + +munit_case(SUBMIT, test_switch_enum_default, { + assert_string_equal(http_to_str((http_error_code_t)999), "Unknown HTTP status code", ""); +}); + +int main() +{ + MunitTest tests[] = { + munit_test("/switch_enum", test_switch_enum), + munit_test("/switch_enum_default", test_switch_enum_default), + munit_null_test, + }; + + MunitSuite suite = munit_suite("http", tests); + + return munit_suite_main(&suite, NULL, 0, NULL); +} diff --git a/src/4-3/http.c b/src/4-3/http.c deleted file mode 100644 index 583ac8c..0000000 --- a/src/4-3/http.c +++ /dev/null @@ -1,7 +0,0 @@ -#include "http.h" - -char* http_to_str(http_error_code_t code) -{ - // ? - return 0; -} diff --git a/src/4-3/main.c b/src/4-3/main.c deleted file mode 100644 index 6c5973a..0000000 --- a/src/4-3/main.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "munit.h" - -#include "http.h" - -munit_case(RUN, test_switch_enum, { - assert_string_equal(http_to_str(HTTP_BAD_REQUEST), "400 Bad Request", ""); - assert_string_equal(http_to_str(HTTP_UNAUTHORIZED), "401 Unauthorized", ""); - assert_string_equal(http_to_str(HTTP_NOT_FOUND), "404 Not Found", ""); - assert_string_equal(http_to_str(HTTP_TEAPOT), "418 I AM A TEAPOT!", ""); - assert_string_equal(http_to_str(HTTP_INTERNAL_SERVER_ERROR), "500 Internal Server Error", ""); -}); - -munit_case(SUBMIT, test_switch_enum_default, { - assert_string_equal(http_to_str((http_error_code_t)999), "Unknown HTTP status code", ""); -}); - -int main() { - MunitTest tests[] = { - munit_test("/switch_enum", test_switch_enum), - munit_test("/switch_enum_default", test_switch_enum_default), - munit_null_test, - }; - - MunitSuite suite = munit_suite("http", tests); - - return munit_suite_main(&suite, NULL, 0, NULL); -} diff --git a/src/4-4-sizeof-enum/main.c b/src/4-4-sizeof-enum/main.c new file mode 100644 index 0000000..5794746 --- /dev/null +++ b/src/4-4-sizeof-enum/main.c @@ -0,0 +1,23 @@ +#include + +typedef enum { + BIG = 123412341234, + BIGGER, + BIGGEST, +} BigNumbers; + +typedef enum { + HTTP_BAD_REQUEST = 400, + HTTP_UNAUTHORIZED = 401, + HTTP_NOT_FOUND = 404, + HTTP_I_AM_A_TEAPOT = 418, + HTTP_INTERNAL_SERVER_ERROR = 500 +} HttpErrorCode; + +int main() +{ + printf("The size of BigNumbers is %zu bytes\n", sizeof(BigNumbers)); + printf("The size of HttpErrorCode is %zu bytes\n", sizeof(HttpErrorCode)); + + return 0; +} diff --git a/src/5-1-union/exercise.c b/src/5-1-union/exercise.c new file mode 100644 index 0000000..a71dc70 --- /dev/null +++ b/src/5-1-union/exercise.c @@ -0,0 +1,34 @@ +#include + +#include "exercise.h" + +void format_object(snek_object_t obj, char* buffer) +{ + switch (obj.kind) { + case INTEGER: + sprintf(buffer, "int:%d", obj.data.v_int); + break; + case STRING: + sprintf(buffer, "string:%s", obj.data.v_string); + break; + }; +} + +// don't touch below this line' + +snek_object_t new_integer(int i) +{ + return (snek_object_t) { + .kind = INTEGER, + .data = { .v_int = i } + }; +} + +snek_object_t new_string(char* str) +{ + // NOTE: We will learn how to copy this data later. + return (snek_object_t) { + .kind = STRING, + .data = { .v_string = str } + }; +} diff --git a/src/5-1-union/exercise.h b/src/5-1-union/exercise.h new file mode 100644 index 0000000..27ee6fe --- /dev/null +++ b/src/5-1-union/exercise.h @@ -0,0 +1,20 @@ +typedef enum SnekObjectKind { + INTEGER, + STRING, +} snek_object_kind_t; + +// don't touch below this line' + +typedef union SnekObjectData { + int v_int; + char* v_string; +} snek_object_data_t; + +typedef struct SnekObject { + snek_object_kind_t kind; + snek_object_data_t data; +} snek_object_t; + +snek_object_t new_integer(int); +snek_object_t new_string(char* str); +void format_object(snek_object_t obj, char* buffer); diff --git a/src/5-1-union/main.c b/src/5-1-union/main.c new file mode 100644 index 0000000..2e96eaf --- /dev/null +++ b/src/5-1-union/main.c @@ -0,0 +1,51 @@ +#include + +#include "exercise.h" +#include "munit.h" + +munit_case(RUN, test_formats_int1, { + char buffer[100]; + snek_object_t i = new_integer(5); + format_object(i, buffer); + + assert_string_equal("int:5", buffer, "formats INTEGER"); +}); + +munit_case(RUN, test_formats_string1, { + char buffer[100]; + snek_object_t s = new_string("Hello!"); + format_object(s, buffer); + + assert_string_equal("string:Hello!", buffer, "formats STRING"); +}); + +munit_case(SUBMIT, test_formats_int2, { + char buffer[100]; + snek_object_t i = new_integer(2014); + format_object(i, buffer); + + assert_string_equal("int:2014", buffer, "formats INTEGER"); +}); + +munit_case(SUBMIT, test_formats_string2, { + char buffer[100]; + snek_object_t s = new_string("nvim btw"); + format_object(s, buffer); + + assert_string_equal("string:nvim btw", buffer, "formats STRING"); +}); + +int main() +{ + MunitTest tests[] = { + munit_test("/integer", test_formats_int1), + munit_test("/string", test_formats_string1), + munit_test("/integer_nvim", test_formats_int2), + munit_test("/string_nvim", test_formats_string2), + munit_null_test, + }; + + MunitSuite suite = munit_suite("format", tests); + + return munit_suite_main(&suite, NULL, 0, NULL); +} diff --git a/src/5-2-memory-layout/main.c b/src/5-2-memory-layout/main.c new file mode 100644 index 0000000..e9a9d7e --- /dev/null +++ b/src/5-2-memory-layout/main.c @@ -0,0 +1,24 @@ +#include +#include + +#include "munit.h" + +typedef union { + int value; + unsigned int err; +} val_or_err_t; + +int main() +{ + val_or_err_t lanes_score = { + .value = -420 + }; + printf("value (set): %d\n", lanes_score.value); + printf("err (unset): %u\n", lanes_score.err); + + val_or_err_t teejs_score = { + .err = UINT_MAX + }; + printf("value (unset): %d\n", teejs_score.value); + printf("err (set): %u\n", teejs_score.err); +} diff --git a/src/5-3-5-4-union-size/main.c b/src/5-3-5-4-union-size/main.c new file mode 100644 index 0000000..5012521 --- /dev/null +++ b/src/5-3-5-4-union-size/main.c @@ -0,0 +1,42 @@ +union SensorData { + long int temperature; + long int humidity; + long int pressure; +}; + +union PacketPayload { + char text[256]; + unsigned char binary[256]; + struct ImageData { + int width; + int height; + unsigned char data[1024]; + } image; +}; + +union Item { + struct { + int damage; + int range; + int size; + } weapon; + struct { + int healingAmount; + int duration; + } potion; + struct { + int doorID; + } key; +}; + +int main() +{ + // Q: How many bytes will an instance of SensorData require? + + // A: 8 bytes + + // Q: Which is the correct order, from least to greatest, of the memory + // requirements of the given unions? + + // A: SensorData, Item, Packetpayload +} diff --git a/src/5-5-helper-fields/exercise.h b/src/5-5-helper-fields/exercise.h new file mode 100644 index 0000000..dacac73 --- /dev/null +++ b/src/5-5-helper-fields/exercise.h @@ -0,0 +1,10 @@ +#include + +typedef union PacketHeader { + struct { + uint16_t src_port; + uint16_t dest_port; + uint32_t seq_num; + } tcp_header; + uint8_t raw[8]; +} packet_header_t; diff --git a/src/5-5-helper-fields/main.c b/src/5-5-helper-fields/main.c new file mode 100644 index 0000000..400fd69 --- /dev/null +++ b/src/5-5-helper-fields/main.c @@ -0,0 +1,53 @@ +#include +#include "exercise.h" +#include "munit.h" + +munit_case(RUN, test_packet_header_size, { + munit_assert_size(sizeof(packet_header_t), ==, 8, "PacketHeader union should be 8 bytes"); +}); + +munit_case(RUN, test_tcp_header_fields, { + packet_header_t header; + header.tcp_header.src_port = 0x1234; + header.tcp_header.dest_port = 0x5678; + header.tcp_header.seq_num = 0x9ABCDEF0; + + munit_assert_uint16(header.tcp_header.src_port, ==, 0x1234, "src_port should be 0x1234"); + munit_assert_uint16(header.tcp_header.dest_port, ==, 0x5678, "dest_port should be 0x5678"); + munit_assert_uint32(header.tcp_header.seq_num, ==, 0x9ABCDEF0, "seq_num should be 0x9ABCDEF0"); +}); + +munit_case(SUBMIT, test_field_raw_size, { + munit_assert_size(sizeof(((packet_header_t*)0)->raw), ==, 8, "PacketHeader union should be 8 bytes"); +}); + +munit_case(SUBMIT, test_field_to_raw_consistency, { + packet_header_t header = { 0 }; + header.tcp_header.src_port = 0x1234; + header.tcp_header.dest_port = 0x5678; + header.tcp_header.seq_num = 0x9ABCDEF0; + + munit_assert_uint8(header.raw[0], ==, 0x34, "[0] should be 0x34"); + munit_assert_uint8(header.raw[1], ==, 0x12, "[1] should be 0x12"); + munit_assert_uint8(header.raw[2], ==, 0x78, "[2] should be 0x78"); + munit_assert_uint8(header.raw[3], ==, 0x56, "[3] should be 0x56"); + munit_assert_uint8(header.raw[4], ==, 0xF0, "[4] should be 0xF0"); + munit_assert_uint8(header.raw[5], ==, 0xDE, "[5] should be 0xDE"); + munit_assert_uint8(header.raw[6], ==, 0xBC, "[6] should be 0xBC"); + munit_assert_uint8(header.raw[7], ==, 0x9A, "[7] should be 0x9A"); +}); + +int main() +{ + MunitTest tests[] = { + munit_test("/test_packet_header_size", test_packet_header_size), + munit_test("/test_tcp_header_fields", test_tcp_header_fields), + munit_test("/test_field_raw_size", test_field_raw_size), + munit_test("/test_field_to_raw_consistency", test_field_to_raw_consistency), + munit_null_test, + }; + + MunitSuite suite = munit_suite("PacketHeader", tests); + + return munit_suite_main(&suite, NULL, 0, NULL); +} diff --git a/src/6-1-the-stack/exercise.h b/src/6-1-the-stack/exercise.h new file mode 100644 index 0000000..f5f0d00 --- /dev/null +++ b/src/6-1-the-stack/exercise.h @@ -0,0 +1,4 @@ +void printMessageOne(); +void printMessageTwo(); +void printMessageThree(); +void printStackPointerDiff(); diff --git a/src/6-1-the-stack/main.c b/src/6-1-the-stack/main.c new file mode 100644 index 0000000..b271e96 --- /dev/null +++ b/src/6-1-the-stack/main.c @@ -0,0 +1,48 @@ +#include "exercise.h" +#include + +int main() +{ + printMessageOne(); + printMessageTwo(); + printMessageThree(); + return 0; +} + +void printMessageOne() +{ + const char* message = "Dark mode?\n"; + printStackPointerDiff(); + printf("%s\n", message); +} + +void printMessageTwo() +{ + const char* message = "More like...\n"; + printStackPointerDiff(); + printf("%s\n", message); +} + +void printMessageThree() +{ + const char* message = "dark roast.\n"; + printStackPointerDiff(); + printf("%s\n", message); +} + +// don't touch below this line + +void printStackPointerDiff() +{ + static void* last_sp = NULL; + void* current_sp; + current_sp = __builtin_frame_address(0); + long diff = (char*)last_sp - (char*)current_sp; + if (last_sp == NULL) { + last_sp = current_sp; + diff = 0; + } + printf("---------------------------------\n"); + printf("Stack pointer offset: %ld bytes\n", diff); + printf("---------------------------------\n"); +} diff --git a/src/6-2-why-a-stack/main.c b/src/6-2-why-a-stack/main.c new file mode 100644 index 0000000..c86b635 --- /dev/null +++ b/src/6-2-why-a-stack/main.c @@ -0,0 +1,9 @@ + +// Q: Generally speaking, it's more performant to store a variable's data on...? + +// - Video casette +// - Ticker tape +// - The stack +// - The heap + +// A: The Stack diff --git a/src/6-3-stack-overflow/main.c b/src/6-3-stack-overflow/main.c new file mode 100644 index 0000000..08d056a --- /dev/null +++ b/src/6-3-stack-overflow/main.c @@ -0,0 +1,16 @@ +#include + +int main() +{ + const int pool_size = 1024 * 10; + char snek_pool[pool_size]; + snek_pool[0] = 's'; + snek_pool[1] = 'n'; + snek_pool[2] = 'e'; + snek_pool[3] = 'k'; + snek_pool[4] = '\0'; + + printf("Size of pool: %d\n", pool_size); + printf("Initial string: %s\n", snek_pool); + return 0; +} diff --git a/src/6-4-pointers-to-the-stack/main.c b/src/6-4-pointers-to-the-stack/main.c new file mode 100644 index 0000000..0241b57 --- /dev/null +++ b/src/6-4-pointers-to-the-stack/main.c @@ -0,0 +1,25 @@ +#include + +typedef struct { + int x; + int y; +} coord_t; + +coord_t new_coord(int x, int y) +{ + coord_t c; + c.x = x; + c.y = y; + return c; +} + +int main() +{ + coord_t c1 = new_coord(10, 20); + coord_t c2 = new_coord(30, 40); + coord_t c3 = new_coord(50, 60); + + printf("c1: %d, %d\n", c1.x, c1.y); + printf("c2: %d, %d\n", c2.x, c2.y); + printf("c3: %d, %d\n", c3.x, c3.y); +} diff --git a/src/6-5-the-heap/exercise.c b/src/6-5-the-heap/exercise.c new file mode 100644 index 0000000..ebc3362 --- /dev/null +++ b/src/6-5-the-heap/exercise.c @@ -0,0 +1,10 @@ +#include "exercise.h" +#include +#include + +char* get_full_greeting(char* greeting, char* name, int size) +{ + char full_greeting[100]; + snprintf(full_greeting, 100, "%s %s", greeting, name); + return full_greeting; +} diff --git a/src/6-5-the-heap/exercise.h b/src/6-5-the-heap/exercise.h new file mode 100644 index 0000000..76ec9b3 --- /dev/null +++ b/src/6-5-the-heap/exercise.h @@ -0,0 +1 @@ +char* get_full_greeting(char* greeting, char* name, int size); diff --git a/src/6-5-the-heap/main.c b/src/6-5-the-heap/main.c new file mode 100644 index 0000000..0c592c0 --- /dev/null +++ b/src/6-5-the-heap/main.c @@ -0,0 +1,44 @@ +#include "exercise.h" +#include "munit.h" +#include +#include + +// Helper function to check if a pointer is on the stack +bool is_on_stack(void* ptr) +{ + void* stack_top = __builtin_frame_address(0); + uintptr_t stack_top_addr = (uintptr_t)stack_top; + uintptr_t ptr_addr = (uintptr_t)ptr; + + // Check within a threshold in both directions (e.g., 1MB) + uintptr_t threshold = 1024; + + return ptr_addr >= (stack_top_addr - threshold) && ptr_addr <= (stack_top_addr + threshold); +} + +munit_case(RUN, test_basic_greeting, { + char* result = get_full_greeting("Hello", "Alice", 20); + munit_assert_string_equal(result, "Hello Alice", "Basic greeting should be correct"); + munit_assert_false(is_on_stack(result)); + free(result); +}); + +munit_case(SUBMIT, test_short_buffer, { + char* result = get_full_greeting("Hey", "Bob", 4); + munit_assert_string_equal(result, "Hey", "Should truncate to fit buffer"); + munit_assert_false(is_on_stack(result)); + free(result); +}); + +int main() +{ + MunitTest tests[] = { + munit_test("/test_basic_greeting", test_basic_greeting), + munit_test("/test_short_buffer", test_short_buffer), + munit_null_test, + }; + + MunitSuite suite = munit_suite("get_full_greeting", tests); + + return munit_suite_main(&suite, NULL, 0, NULL); +} diff --git a/src/munit.h b/src/munit.h new file mode 100644 index 0000000..bfdda81 --- /dev/null +++ b/src/munit.h @@ -0,0 +1,57 @@ +#include "../vendor/munit/munit.h" + +// TJ seems to have added a bunch of macros to the default munit.h, +// implement those here + +// ----------------------------------------- +// Test suite macros + +#define munit_case(NAME, FUNCNAME, BODY) \ + static MunitResult FUNCNAME(const MunitParameter params[], void* data) \ + { \ + (void)params; \ + (void)data; \ + BODY return MUNIT_OK; \ + } + +#define munit_test(NAME, FN) \ + { NAME, FN, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } + +#define munit_null_test \ + { NULL, NULL, NULL, NULL, MUNIT_TEST_OPTION_NONE, NULL } + +#define munit_suite(NAME, TESTS) \ + (MunitSuite) { NAME, TESTS, NULL, 1, MUNIT_SUITE_OPTION_NONE } + +// ----------------------------------------- +// Overwrite assertion macros, extended with "msg" parameter + +#undef assert_int +#define assert_int(A, OP, B, MSG) \ + munit_assert_int(A, OP, B); + +#undef assert_uint +#define assert_uint(A, OP, B, MSG) \ + munit_assert_uint(A, OP, B); + +#undef assert_double +#define assert_double(A, OP, B, MSG) \ + munit_assert_double(A, OP, B); + +#undef assert_string_equal +#define assert_string_equal(A, B, MSG) \ + munit_assert_string_equal(A, B); + +#undef munit_assert_size +#define munit_assert_size(A, OP, B, MSG) \ + munit_assert_type(size_t, MUNIT_SIZE_MODIFIER "u", A, OP, B) + +#undef munit_assert_uint8 +#define munit_assert_uint8(A, OP, B, MSG) \ + munit_assert_type(munit_uint8_t, PRIu8, A, OP, B) +#undef munit_assert_uint16 +#define munit_assert_uint16(A, OP, B, MSG) \ + munit_assert_type(munit_uint16_t, PRIu16, A, OP, B) +#undef munit_assert_uint32 +#define munit_assert_uint32(A, OP, B, MSG) \ + munit_assert_type(munit_uint32_t, PRIu32, A, OP, B)