Object-orientation in C

前端 未结 22 1552
孤城傲影
孤城傲影 2020-11-22 15:26

What would be a set of nifty preprocessor hacks (ANSI C89/ISO C90 compatible) which enable some kind of ugly (but usable) object-orientation in C?

I am familiar with

22条回答
  •  心在旅途
    2020-11-22 16:14

    I used to do this kind of thing in C, before I knew what OOP was.

    Following is an example, which implements a data-buffer which grows on demand, given a minimum size, increment and maximum size. This particular implementation was "element" based, which is to say it was designed to allow a list-like collection of any C type, not just a variable length byte-buffer.

    The idea is that the object is instantiated using the xxx_crt() and deleted using xxx_dlt(). Each of the "member" methods takes a specifically typed pointer to operate on.

    I implemented a linked list, cyclic buffer, and a number of other things in this manner.

    I must confess, I have never given any thought on how to implement inheritance with this approach. I imagine that some blend of that offered by Kieveli might be a good path.

    dtb.c:

    #include 
    #include 
    #include 
    
    static void dtb_xlt(void *dst, const void *src, vint len, const byte *tbl);
    
    DTABUF *dtb_crt(vint minsiz,vint incsiz,vint maxsiz) {
        DTABUF          *dbp;
    
        if(!minsiz) { return NULL; }
        if(!incsiz)                  { incsiz=minsiz;        }
        if(!maxsiz || maxsizmaxsiz)     { incsiz=maxsiz-minsiz; }
        if((dbp=(DTABUF*)malloc(sizeof(*dbp))) == NULL) { return NULL; }
        memset(dbp,0,sizeof(*dbp));
        dbp->min=minsiz;
        dbp->inc=incsiz;
        dbp->max=maxsiz;
        dbp->siz=minsiz;
        dbp->cur=0;
        if((dbp->dta=(byte*)malloc((vuns)minsiz)) == NULL) { free(dbp); return NULL; }
        return dbp;
        }
    
    DTABUF *dtb_dlt(DTABUF *dbp) {
        if(dbp) {
            free(dbp->dta);
            free(dbp);
            }
        return NULL;
        }
    
    vint dtb_affffdta(DTABUF *dbp,const byte *xlt256,const void *dtaptr,vint dtalen) {
        if(!dbp) { errno=EINVAL; return -1; }
        if(dtalen==-1) { dtalen=(vint)strlen((byte*)dtaptr); }
        if((dbp->cur + dtalen) > dbp->siz) {
            void        *newdta;
            vint        newsiz;
    
            if((dbp->siz+dbp->inc)>=(dbp->cur+dtalen)) { newsiz=dbp->siz+dbp->inc; }
            else                                       { newsiz=dbp->cur+dtalen;   }
            if(newsiz>dbp->max) { errno=ETRUNC; return -1; }
            if((newdta=realloc(dbp->dta,(vuns)newsiz))==NULL) { return -1; }
            dbp->dta=newdta; dbp->siz=newsiz;
            }
        if(dtalen) {
            if(xlt256) { dtb_xlt(((byte*)dbp->dta+dbp->cur),dtaptr,dtalen,xlt256); }
            else       { memcpy(((byte*)dbp->dta+dbp->cur),dtaptr,(vuns)dtalen);   }
            dbp->cur+=dtalen;
            }
        return 0;
        }
    
    static void dtb_xlt(void *dst,const void *src,vint len,const byte *tbl) {
        byte            *sp,*dp;
    
        for(sp=(byte*)src,dp=(byte*)dst; len; len--,sp++,dp++) { *dp=tbl[*sp]; }
        }
    
    vint dtb_addtxt(DTABUF *dbp,const byte *xlt256,const byte *format,...) {
        byte            textÝ501¨;
        va_list         ap;
        vint            len;
    
        va_start(ap,format); len=sprintf_len(format,ap)-1; va_end(ap);
        if(len<0 || len>=sizeof(text)) { sprintf_safe(text,sizeof(text),"STRTOOLNG: %s",format); len=(int)strlen(text); }
        else                           { va_start(ap,format); vsprintf(text,format,ap); va_end(ap);                     }
        return dtb_affffdta(dbp,xlt256,text,len);
        }
    
    vint dtb_rmvdta(DTABUF *dbp,vint len) {
        if(!dbp) { errno=EINVAL; return -1; }
        if(len > dbp->cur) { len=dbp->cur; }
        dbp->cur-=len;
        return 0;
        }
    
    vint dtb_reset(DTABUF *dbp) {
        if(!dbp) { errno=EINVAL; return -1; }
        dbp->cur=0;
        if(dbp->siz > dbp->min) {
            byte *newdta;
            if((newdta=(byte*)realloc(dbp->dta,(vuns)dbp->min))==NULL) {
                free(dbp->dta); dbp->dta=null; dbp->siz=0;
                return -1;
                }
            dbp->dta=newdta; dbp->siz=dbp->min;
            }
        return 0;
        }
    
    void *dtb_elmptr(DTABUF *dbp,vint elmidx,vint elmlen) {
        if(!elmlen || (elmidx*elmlen)>=dbp->cur) { return NULL; }
        return ((byte*)dbp->dta+(elmidx*elmlen));
        }
    

    dtb.h

    typedef _Packed struct {
        vint            min;                /* initial size                       */
        vint            inc;                /* increment size                     */
        vint            max;                /* maximum size                       */
        vint            siz;                /* current size                       */
        vint            cur;                /* current data length                */
        void            *dta;               /* data pointer                       */
        } DTABUF;
    
    #define dtb_dtaptr(mDBP)                (mDBP->dta)
    #define dtb_dtalen(mDBP)                (mDBP->cur)
    
    DTABUF              *dtb_crt(vint minsiz,vint incsiz,vint maxsiz);
    DTABUF              *dtb_dlt(DTABUF *dbp);
    vint                dtb_affffdta(DTABUF *dbp,const byte *xlt256,const void *dtaptr,vint dtalen);
    vint                dtb_addtxt(DTABUF *dbp,const byte *xlt256,const byte *format,...);
    vint                dtb_rmvdta(DTABUF *dbp,vint len);
    vint                dtb_reset(DTABUF *dbp);
    void                *dtb_elmptr(DTABUF *dbp,vint elmidx,vint elmlen);
    

    PS: vint was simply a typedef of int - I used it to remind me that it's length was variable from platform to platform (for porting).

提交回复
热议问题