{"id":18047975,"url":"https://github.com/neorandom/class-in-c","last_synced_at":"2026-01-22T02:04:40.118Z","repository":{"id":259990432,"uuid":"865062270","full_name":"neoRandom/class-in-c","owner":"neoRandom","description":"How to implement classes in C.","archived":false,"fork":false,"pushed_at":"2024-09-30T06:27:07.000Z","size":19,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-24T08:08:32.007Z","etag":null,"topics":["c","c-language","class","classes","classes-and-objects","low-level","low-level-programming","objects","pointers","pointers-in-c","pointers-to-functions"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/neoRandom.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-09-29T22:04:30.000Z","updated_at":"2024-09-30T11:27:40.000Z","dependencies_parsed_at":"2024-10-29T00:25:56.071Z","dependency_job_id":"451209ad-dc82-4771-93f6-c4de31f16b50","html_url":"https://github.com/neoRandom/class-in-c","commit_stats":null,"previous_names":["neorandom/class-in-c"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoRandom%2Fclass-in-c","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoRandom%2Fclass-in-c/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoRandom%2Fclass-in-c/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/neoRandom%2Fclass-in-c/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/neoRandom","download_url":"https://codeload.github.com/neoRandom/class-in-c/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248190407,"owners_count":21062277,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","c-language","class","classes","classes-and-objects","low-level","low-level-programming","objects","pointers","pointers-in-c","pointers-to-functions"],"created_at":"2024-10-30T20:10:24.064Z","updated_at":"2026-01-22T02:04:40.077Z","avatar_url":"https://github.com/neoRandom.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Classes in C\n\n\u003e \"Most good programmers do programming not because they expect to get paid or get adulation by the public, but because it is fun to program.\" -Linus Torvalds\n\nThis project is about constructing classes in C with my low experience with this type of thing.\n\nIn the proccess of learning how, I will pass through what a pointer is, what a struct is and, of course, what a class is.\n\nDon't expect to be good as some of these big projects that a professional with years of experience make, also because it's on the earliest versions. Besides that, I'm trying my best to provide correct and rich informations about this subject.\n\nThere is lots of things to improve, polish and finish.\n\n\n---\n- [Introduction](#introduction)\n\t- [What is a pointer](#what-is-a-pointer)\n\t\t- [Pointer Arithmetic](#pointer-arithmetic)\n\t- [What is a structure](#what-is-a-structure)\n\t- [What is a function](#what-is-a-function)\n- [Developing the Class system](#developing-the-class-system)\n\t- [Starting the development](#starting-the-development)\n\t\t- [Adding a way to make non-static methods](#adding-a-way-to-make-non-static-methods)\n\t- [Advanced system development](#advanced-system-development)\n\t\t- [Adding a destructor function](#adding-a-destructor-function)\n\t\t- [Improving the performance](#improving-the-performance)\n\t\t- [Creating an access modifier system](#creating-an-access-modifier-system)\n---\n\n# Introduction\n\n\u003e\"A structure is just a fancy pointer, and a class is just a fancy structure.\"\n\nKnowing this, we can first thought of what a class is composed of, and it's about this:\n- Attributes\n- Methods\n\nWell, attributes are already built-in in the structures, so our problem is just the methods.\n\nBut, before we start our development, what is a pointer?\n\n## What is a pointer\n\nA pointer is a variable that stores some memory address. It can be found with the size of 8 bytes in a 64-bits processor, 4 bytes in a 32-bits processor and 2 bytes in a 16-bits processor.\n\nAll the pointers necessity is based on the access of memory with some address as reference.\n\nWe can imagine as a road, you can reference a house based on the start of the street, but this is bad when you have multiple deliveries, some complex ones, and a long street. So, you start to reference by something closer, and that is the pointer.\n\nAlso, pointers are what is used to create raw arrays, by using pointer arithmetic.\n\nPointers can have types, from primitive/primary types to structures. They don't change the content of the pointer, but how the compiler see the pointer and consequently how the arithmetic is made. \n\nBut what is that `pointer artihmentic` that was mentioned so many times?\n### Pointer Arithmetic\n\nPointer arithmetic is simple, is just take the address of the pointer and sum with a value to get another address value.\n\nImagine that this table is the memory:\n\n| Address (hex) | Value (binary) |\n| ------------- | -------------- |\n| 0000          | 0000 0000      |\n| 0001          | 0000 0000      |\n| 0002          | 0000 0000      |\n| 0003          | 0000 0000      |\n| 0004          | 0000 0000      |\n| 0005          | 0000 0000      |\n| 0006          | 1111 1111      |\n| 0007          | 1111 1000      |\n| [...]         | [...]          |\n| FFF8          | 0000 0000      |\n| FFF9          | 0000 0000      |\n| FFFA          | 0000 0000      |\n| FFFB          | 0000 0101      |\n| FFFC          | 0000 0000      |\n| FFFD          | 0000 0000      |\n| FFFE          | 0000 0000      |\n| FFFF          | 0000 1010      |\n\nAt the address 0000x0 there is an int pointer at the stack that the value is FFF8x0, so it points to a int at the heap with value 5. If it is an array, to get the next element, it need to get the int at the address `FFF8x0 + 0004x0`, and that is easily done with `pointer[1]`.\n\nAnd that is where the pointer type comes to play. The compiler only knows that you need to add 4 (bytes) because the size of an int is 4 bytes.\n\n\u003ePointer arithmetic with structures is a bit more complex, the explanation is TBA.\n\n## What is a structure\n\nA structure is a way that C deals with the problems when the project begins to be too large and has problems with the amount of variables and the lack of pattern rules between then.\n\nHere is an example of structure:\n``` c\nstruct Person {\n\tchar *name;\n\tint age;\n}\n\nstruct Person person;\nperson.name = \"rakRandom\";\nperson.age = 16;\n```\n\nStructs can also be transformed into a type by using the `typedef` keyword, like this:\n``` c\ntypedef struct Person {\n\tchar *name;\n\tint age;\n}\n\nPerson person;\nperson.name = \"rakRandom\";\nperson.age = 16;\n```\n\nDiving deeper into what a struct is, it is a way to store variables inside them, and that is all. But while this concept is simple, the fact that these variables can be pointers is interesting for us, that want to create a Class in C.\n\nOne of the types of pointers that can be created is the function pointer. But, before going further, what is, in fact, a function or method?\n\n## What is a function\n\nBasically, a function is a bunch of machine code that generally are stored at the executable file and then passed to the `.code` memory area. But what we use to call the function when we are programming is not exactly the function, it is a pointer to it.\n\nWe can define a function pointer in C using the following syntax rule:\n\n`\u003creturn type\u003e (*\u003cvariable name/function name\u003e)(\u003cparameter types\u003e)`\n\n\u003e _Yes, it was all pointers, from the beginning to the end._\n\nHere is an example:\n``` c\n#include \u003cstdio.h\u003e  // C Standart Input/Output library\n\n// Original function\nint my_add_function(int x, int y) {\n    return x + y;\n}\n\nint main() {\n    // Pointer that points to the same memory space as 'my_add_function'\n    int (*add)(int,int) = my_add_function;\n    \n    printf(\"%d\\n\", add(1, 1)); // Output: 2\n    \n    return 0;\n}\n```\n\n# Developing the Class system\n\n## Starting the development\n\nWith all this in mind, we can start to develop our system, it should look something like this:\n\n\u003e`thing.h`\n``` c\ntypedef struct {\n    void (*showThing)();\n} Thing;\n```\n\nThen, we define the struct pointer value as the same as the function `showThing` address:\n\u003e`main.c`\n``` c\n#include \u003cstdio.h\u003e\n#include \"thing.h\"\n\nvoid showThing() {\n    printf(\"Something!\\n\");\n}\n\nint main() {\n    Thing thing;\n\n    thing.showThing = showThing;\n}\n```\n\nBut there is a problem, we don't know yet how to make a non-static method.\n\nA non-static method depends on the object, it can reference the object and its attributes. So, how can you do this?\n\n### Adding a way to make non-static methods\n\nIf we try to do this by passing the pointer as a parameter, this happens:\n``` c\ntypedef struct {\n    void (*showThing)(Thing*);  // Error: `Thing` is not declared\n} Thing;\n```\n\nWe can't say that a `Thing` pointer type variable is passed as parameter, because it wasn't created yet.\n\nTo fix this, we can use a `void` pointer to represent an `Any`-like type or a generic `\u003cT\u003e` thing.\n\nBut life doesn't go so smooth and, besides being ass ugly, it throws a `-Wincompatible-pointer-types` error if compiled with GCC, because it doesn't recognize `void *` as a generic or some shit like that.\n\n\u003eNote: In most online compilers, this approach will work.\n\nTo fix this two issues (being ugly and error prone), we need to go back to a basic function concept.\n\nWhy are the functions just _generally_ stored at the executable file and then passed to the `.code` memory area? Well, because it is possible to create functions at execution time, and then they will be store at the heap with a pointer to them being available.\n\nHere is an example:\n``` c\nvoid outer() {\n\tvoid inner() {\n\t\tprintf(\"Hello, I was created in execution time!\\n\");\n\t}\n\n\tinner();\n}\n```\n\nFurthermore, we can mix this concept with scopes.\n\nScope is the area of the code where the application is currently on, if a variable is defined inside a scope, it will not be accessible at the outer scope, but the opposite is not true and, in fact, it's the opposite, a variable defined in an outer scope, when in the inner scope, it will be accessible, and we can use this to create relative references at execution time.\n\nAfter applying these concepts, it should look like this:\n``` c\nvoid outer() {\n\tint age = 16;\n\t\n\tvoid inner() {\n\t\tprintf(\"Hi, I'm %d years old!\\n\", age);\n\t}\n\n\tinner();\n}\n\nouter();  // Hi, I'm 16 years old!\n```\n\n## Advanced system development\n\nFixing these errors, we can finally work on the class system, with attributes and static and non-static methods.\n\nFirst, we don't want to manually set all the methods every time we instantiate an object, so we need a `constructor`. And to do this, we need to:\n- First: change the `outer` function return type to a pointer of the struct desired, like a `Thing` pointer.\n- Second: create a variable that is a struct pointer called `new` with `malloc` or `calloc` and return it at the end of the function.\n- Third: change the name `outer` to `new\u003cclass name\u003e` (e.g.: `newThing`).\n- Fourth: change the name `inner` to `\u003cmethod name\u003e` (e.g.: `showThing`).\n- Fifth: set the `new` function pointer attribute(s) as the inner function(s).\n\nThe `outer` function will become the object constructor, and the inner function(s) will be the the method(s).\n\nHere is an example with the `Thing` structure:\n\u003e`thing.h`\n``` c\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n\ntypedef struct {\n    void (*showThing)();\n} Thing;\n\nThing * newThing();\n```\n\n\u003e`thing.c`\n``` c\n#include \"thing.h\"\n\nThing * newThing() {\n    Thing *new = (Thing*) malloc(sizeof(Thing));\n\n    void showThing() {\n        printf(\"Something!\\n\");\n    }\n    \n    new-\u003eshowThing = showThing;\n\n    return new;\n}\n```\n\n\u003e`main.c`\n``` c \n#include \"thing.h\"\n\nint main() {\n    Thing *thing = newThing();\n    thing-\u003eshowThing();  // Output: Something!\n    free(thing);  // Don't forget to free the pointers!\n}\n```\n\n### Adding a `destructor` function\n\nTo improve even more, we can add a `destructor` to our class, like this:\n\n\u003e`thing.h`\n``` c\n[...]\n\nvoid deleteThing(Thing *thing);\n```\n\n\u003e`thing.c`\n``` c\n[...]\n\nvoid deleteThing(Thing *thing) {\n    free(thing);\n}\n```\n\n\u003e`main.c`\n``` c\n#include \"thing.h\"\n\nint main() {\n    Thing *thing = newThing();\n    thing-\u003eshowThing();  // Output: Something!\n    deleteThing(thing);  // New way to delete the object!\n}\n```\n\nIn this example the `destructor` is very simple, but in bigger classes, with pointers or other classes as attributes, it's essential to have a `destructor`.\n\n### Improving the performance\n\nIn our previous case, the constructor function created all the method code every time an object was created, and this can lead to a high memory usage.\n\nTo fix it, we can create a \"private\" function before the constructor, and then, inside the constructor, create a wrapper to this function, like this:\n\n\u003e`thing.h`\n``` c\n#include \u003cstdio.h\u003e\n#include \u003cstdlib.h\u003e\n\ntypedef struct {\n    int someAttribute;\n    void (*showThing)();\n} Thing;\n\nThing * newThing();\n```\n\n\u003e`thing.c`\n``` c\n#include \"thing.h\"\n\nvoid _showThing(Thing * thing) {\n\tprintf(\"Something %d!\\n\", thing-\u003esomeAttribute);\n}\n\nThing * newThing() {\n    Thing *new = (Thing*) malloc(sizeof(Thing));\n\n    void showThing() {\n        _showThing(new);\n    }\n    \n    new-\u003eshowThing = showThing;\n\n    return new;\n}\n```\n\nThis way, we can let the big code be created just once, and change the reference as the objects are created, with just one line.\n\n### Creating an access modifier system\n\n\u003e_To be tested_\n\nTBA\n\n## License\n\nThis project is currently under a [MIT License](LICENSE)\n\n\u003cbr /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneorandom%2Fclass-in-c","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fneorandom%2Fclass-in-c","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fneorandom%2Fclass-in-c/lists"}