Try   HackMD

C 也可以寫的很OOP 簡單範例與簡易Makefile

tags: C LANGUAGE oop Object-oriented programming C99 ring buffer

Author: CrazyMonkey
email: kccddb@gmail.com
Date: 20230214
Copyright: CC BY-NC-SA

  1. 了解這例子可以更深刻了解
    物件導向程式設計(OOP :Object-oriented programming) , 例如 java, javascript,
  2. 了解 this 的意義, 這裡也用到 function pointer
  3. object 的生成(constructor)與回收(deconstructor)需要付出 garbage collection 的代價, 如果於迴圈中大量使用將可能大量消耗記憶體與CPU資源.
//crect.c /* * *Copyright (C) 2019 My-Company-Name *Version: 1.101 2019/01/01 *Authors: WhoAmI, <whomani@xxxgmail.com> *Complie and Link: * gcc -Wall -c crect.c -o crect.o * *TODO: Homework, DUE DATE: 2019/01/01 * *BUGS: */ #include <stdlib.h> #include "crect.h" static void SetParameter(CRectangle *rect,int a, int b) { //"this" pointer rect->width=a; rect->height=b; } static int GetArea(CRectangle *rect) { return (rect->width)* (rect->height); } //global functions //constructor CRectangle *init_CRectangle(int width,int height) { CRectangle *pThis ; //allocte object storage pThis=(CRectangle *)malloc(sizeof(CRectangle)); if(pThis){ //assign function pointers and properties pThis->set_parameters = SetParameter; pThis->area=GetArea; pThis->width=width; pThis->height=height; } return pThis; } //deconstructor int exit_CRectangle(CRectangle *pThis){ if(pThis){ free(pThis); //release object return 0; } return -1; } //crect.h typedef struct Rectangle{ int width, height; int (*area) (struct Rectangle *); void (*set_parameters )( struct Rectangle *,int,int); }CRectangle; CRectangle *init_CRectangle(int width,int height); int exit_CRectangle(CRectangle *pThis); /* app.c demo gcc app.c crect.c -o app */ #include <stdio.h> #include "crect.h" int main () { CRectangle *rect; //init object rect=init_CRectangle(5,3); //allocate memory and initialize object if(!rect){ printf("Cannot init CRectangle\n"); } rect->set_parameters (rect,2,4); printf("area:%d\n", rect->area(rect)); //exit exit_CRectangle(rect); //release object return 0; }

HW. 設計一 CPolygon (多邊形)
CPolygon *init_CPolygon(int edges,);
//計算周長
int (*Perimeter) (struct Polygon *);
int exit_CRectangle(CPolygon *pThis);

Hint:
stdarg, va_start, va_arg, va_end, va_copy - variable argument lists

簡易的 Makefile

當您改變 CC, CFLAGS, LDFLAGS, 等可以改變為不同 CPU, 如此以後才方便移植至其他 SoC!

CC = gcc AR = ar RANLIB = ranlib STRIP = strip CFLAGS = -Wall -DDEBUG0 LDFLAGS= -lpthread CSOURCE= crect.c app.c all: homework2 homework2: ${CSOURCE} ${CC} ${CSOURCE} ${CFLAGS} -o app ${STRIP} app clean: rm app

ar - create, modify, and extract from archives
ranlib - generate an index to an archive

使用 gcc 自製 C/C++ 靜態、共享與動態載入函式庫教學, by G. T. Wang


C99, Linux kernel 大都使用此寫法

#include <stdio.h> #include <stdlib.h> /* C99 gcc xxx -std=c99 */ typedef struct student{ int id; int (*year)(struct student * ); int score; } Student; static int year (struct student *pthis){ return pthis->id; } int main(int argc, char *argv[]){ Student s= (Student) {.id=10,.year=year,}; printf("year=%d\n",s.year(&s)); }

drivers/char/misc.c

static struct file_operations misc_proc_fops = {.owner = THIS_MODULE,.open = misc_seq_open,.read = seq_read,.llseek = seq_lseek,.release = seq_release, };

ring buffer

簡單但實用的 ring buffer (circular buffer, circular queue and cyclic buffer) , 請自行測試
尤其是記憶體受限時, 例如 單晶片, embedded system 或資料變動快速與大量時(使用ring buffer (fixed maximum size) 不需要 經常 malloc, free, 如此可減少 OS 進行 garbage collection! )

有次 研發人員 處理 快速大量資料時(每次大小不一定) 用 linked list, 改建議 他使用 ring buffer.

Ring Buffer OOP version

/* * *Copyright CC BY-NC-SA *Version: *Authors: WhoAmI *Complie and Link: * * *TODO: * *BUGS: */ #include <stdlib.h> #include <string.h> #include <errno.h> #include <unistd.h> typedef struct ring_buffer { void *buffer; // data buffer void *buffer_end; // end of data buffer size_t capacity; // maximum number of items in the buffer size_t count; // number of items in the buffer size_t sz; // size of each item in the buffer void *head; // pointer to head void *tail; // pointer to tail } ring_buffer; ring_buffer * ring_init( size_t capacity, size_t sz) { ring_buffer *ring; ring=malloc(sizeof(ring_buffer)); if(ring==NULL)return NULL; ring->buffer = malloc(capacity * sz); if(ring->buffer == NULL){ free(ring); return NULL; } ring->buffer_end = (unsigned char *)ring->buffer + capacity * sz; ring->capacity = capacity; ring->count = 0; ring->sz = sz; ring->head = ring->buffer; ring->tail = ring->buffer; } void ring_exit(ring_buffer *ring) { if(ring){ free(ring->buffer); free(ring); } } int ring_push(ring_buffer *ring, const void *item) { if(ring->count == ring->capacity){ return 0; } memcpy(ring->head, item, ring->sz); ring->head = (unsigned char*)ring->head + ring->sz; if(ring->head == ring->buffer_end) ring->head = ring->buffer; ring->count++; return ring->count; } int ring_pop(ring_buffer *ring, void *item) { if(ring->count == 0){ // handle error return 0; } memcpy(item, ring->tail, ring->sz); ring->tail = (unsigned char*)ring->tail + ring->sz; if(ring->tail == ring->buffer_end) ring->tail = ring->buffer; ring->count--; return ring->count; }