Hiding members in a C struct

前端 未结 14 2021
渐次进展
渐次进展 2020-11-29 21:02

I\'ve been reading about OOP in C but I never liked how you can\'t have private data members like you can in C++. But then it came to my mind that you could create 2 structu

14条回答
  •  悲哀的现实
    2020-11-29 21:22

    I found that bit-field might be a good solution if you really want to hide something.

    struct person {
        unsigned long :64;
        char          *name;
        int           age;
    };
    
    struct wallet {
        char *currency;
        double balance;
    };
    

    The first member of struct person is an unnamed bit-field. used for a 64-bit pointer in this case. It's completely hidden and cannot be accessed by struct variable name.

    Because of the first 64-bit in this struct is unused, so we can use it as a private pointer. We can access this member by its memory address instead of variable name.

    void init_person(struct person* p, struct wallet* w) {
        *(unsigned long *)p = (unsigned long)w;
        // now the first 64-bit of person is a pointer of wallet
    }
    
    struct wallet* get_wallet(struct person* p) {
        return (struct wallet*)*(unsigned long *)p;
    }
    

    A small working example, tested on my intel mac:

    //
    // Created by Rieon Ke on 2020/7/6.
    //
    
    #include 
    #include 
    #include 
    
    
    #if __x86_64__ || __LP64__
    #define PRIVATE_SET(obj, val) *(unsigned long *) obj = (unsigned long) val;
    #define PRIVATE_GET(obj, type) (type)*(unsigned long *) obj;
    #define PRIVATE_POINTER unsigned long:64
    #else
    #define PRIVATE_SET(obj, val) *(unsigned int *) obj = (unsigned int) val;
    #define PRIVATE_GET(obj, type) (type)*(unsigned int *) obj;
    #define PRIVATE_POINTER unsigned int:32
    #endif
    
    struct person {
        PRIVATE_POINTER;
        char *name;
        int age;
    };
    
    struct wallet {
        char *currency;
        double balance;
    };
    
    int main() {
    
        struct wallet w;
        w.currency = strdup("$$");
        w.balance = 99.9;
    
        struct person p;
        PRIVATE_SET(&p, &w) //set private member
    
        p.name = strdup("JOHN");
        p.age = 18;
    
        struct wallet *pw = PRIVATE_GET(&p, struct wallet*) //get private member
    
        assert(strcmp(pw->currency, "$$") == 0);
        assert(pw->balance == 99.9);
    
        free(w.currency);
        free(p.name);
    
        return 0;
    }
    

提交回复
热议问题