Skip to content

Commit

Permalink
+11-struct
Browse files Browse the repository at this point in the history
  • Loading branch information
hengxin committed Dec 11, 2024
1 parent f7fc2ad commit e81ec01
Show file tree
Hide file tree
Showing 14 changed files with 867 additions and 0 deletions.
4 changes: 4 additions & 0 deletions 11-struct/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
add_executable(musician musician.c)
add_executable(padding offset.c)
add_executable(sds sds.c)
add_executable(sds-202412 sds-202412.c)
33 changes: 33 additions & 0 deletions 11-struct/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# `12-struct`

- `struct`
- `struct musician`
- `typedef struct musician`
- **struct alignment and padding**
- `typedef struct score`
- `enum`
- `struct` assignment
- `PrintMusician(const Musician m)`
- `PrintMusician(const Musician *m)`

## c-reference

- `struct`
- `flexible array`

## padding

## `offsetof` and `container_of`

- [offsetof @ wikipedia](https://en.wikipedia.org/wiki/Offsetof)
- [offsetof @ cref](https://en.cppreference.com/w/c/types/offsetof)
- [offsetof @ stackoverflow](https://stackoverflow.com/q/26906621/1833118)
- [container_of @ stackoverflow](https://stackoverflow.com/q/15832301/1833118)
- [container_of @ radek.io](https://radek.io/posts/magical-container_of-macro/)
- [container_of @ Linux Kernel Monkey Log](http://www.kroah.com/log/linux/container_of.html)
- [container_of @ 0xAX](https://0xax.gitbooks.io/linux-insides/content/DataStructures/linux-datastructures-1.html)

## Union

- [union in
`dictEntry` @ redis](https://github.com/redis/redis/blob/c51c96656bf1f1801ae90a376f71890cbcdea4b4/src/dict.c#L47-L134)
187 changes: 187 additions & 0 deletions 11-struct/musician.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
// Created by hfwei on 2024/12/11.

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>

typedef enum gender {
MALE,
FEMALE,
GENDER_KINDS,
} Gender;

typedef struct score {
int c_score;
int java_score;
int python_score;
} Score;

typedef struct musician {
char *name;
// char gender;
Gender gender;
struct tm birth;

char *album;

Score score;

union {
int performances; // number of performances
double funding; // funding in millions
int awards; // number of awards won
char *highlight; // textual highlight of the yea
} year_end_summary;

enum {
PERFORMANCES,
FUNDING,
AWARDS,
HIGHLIGHT
} summary_type;
} Musician;

// void PrintMusician(const Musician m);
void PrintMusician(const Musician *m);
int CompareMusician(const void *m1, const void *m2);

int main(void) {
printf("sizeof(Score) = %zu\n", sizeof(Score));
printf("sizeof(Musician) = %zu\n", sizeof(Musician));
printf("offsetof(Musician, name) = %zu\n", offsetof(Musician, name));
printf("offsetof(Musician, gender) = %zu\n", offsetof(Musician, gender));
printf("offsetof(Musician, album) = %zu\n", offsetof(Musician, album));
printf("offsetof(Musician, score) = %zu\n", offsetof(Musician, score));

Musician luo = {
.name = "Luo Dayou",
.gender = MALE,
.birth = {
.tm_year = 1954 - 1900,
.tm_mon = 7 - 1,
.tm_mday = 20,
.tm_wday = 2, // Tuesday
},
.album = "ZhiHuZheYe",
.score = {
.c_score = 0,
.java_score = 10,
.python_score = 20,
},
.year_end_summary.performances = 20,
.summary_type = PERFORMANCES,
};

Musician cui = {
.name = "Cui Jian",
.gender = MALE,
.birth = {
.tm_year = 1961 - 1900,
.tm_mon = 8 - 1,
.tm_mday = 2,
.tm_wday = 3, // Wednesday
},
.album = "XinChangZhengLuShangDeYaoGun",
.score = {
.c_score = 10,
.java_score = 20,
.python_score = 30,
},
.year_end_summary.funding = 2.5,
.summary_type = FUNDING,
};

char album[] = "YiKeBuKenMeiSuDeXin";
Musician zhang = {
.name = "Zhang Chu",
.gender = MALE,
.birth = {
.tm_year = 1968 - 1900,
.tm_mon = 11 - 1,
.tm_mday = 17,
.tm_wday = 0, // Sunday
},
// .album = "YiKeBuKenMeiSuDeXin",
.album = album,
.score = {
.c_score = 20,
.java_score = 30,
.python_score = 40,
},
// https://www.bilibili.com/video/BV1f6i2YZEMJ/
.year_end_summary.awards = 2,
.summary_type = AWARDS,
};

Musician guo = zhang;
guo.name = "Guo Fucheng";
strcpy(guo.album, "YiKeJiuMeiSuDeXin");
// PrintMusician(guo);
// PrintMusician(zhang);
PrintMusician(&guo);
PrintMusician(&zhang);

Musician musicians[] = {luo, cui, zhang,};
int len = sizeof musicians / sizeof *musicians;
for (int i = 0; i < len; ++i) {
// PrintMusician(musicians[i]);
PrintMusician(&musicians[i]);
}

qsort(musicians, len,
sizeof *musicians,
CompareMusician);

for (int i = 0; i < len; ++i) {
// PrintMusician(musicians[i]);
PrintMusician(&musicians[i]);
}

return 0;
}

// void PrintMusician(const Musician m) {
// printf("\n%s\t%d\t%s\t%d\t%d\t%d\n",
// m.name,
// m.gender,
// m.album,
// m.score.c_score,
// m.score.java_score,
// m.score.python_score);
// }

void PrintMusician(const Musician *m) {
printf("\n%s\t%d\t%s\t%s\t%d\t%d\t%d\n",
m->name,
m->gender,
asctime(&m->birth),
m->album,
m->score.c_score,
m->score.java_score,
m->score.python_score);

switch (m->summary_type) {
case PERFORMANCES:printf("Performed %d times\n", m->year_end_summary.performances);
break;
case FUNDING:printf("Secured $%.2fM in funding\n", m->year_end_summary.funding);
break;
case AWARDS:printf("Won %d awards\n", m->year_end_summary.awards);
break;
case HIGHLIGHT:printf("%s\n", m->year_end_summary.highlight);
break;
}
}

int CompareMusician(const void *m1, const void *m2) {
const Musician *m_left = m1;
const Musician *m_right = m2;

return strcmp(m_left->album, m_right->album);

// char *name_left = *(char **) m1;
// char *name_right = *(char **) m2;

// return strcmp(name_left, name_left);
}
35 changes: 35 additions & 0 deletions 11-struct/offset.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Created by hfwei on 2024/12/10.

#include <stdio.h>
//#include <stddef.h>

// creference: https://en.cppreference.com/w/c/types/offsetof
// Magic: https://radek.io/posts/magical-container_of-macro/
// StackOverflow: https://stackoverflow.com/q/15832301/1833118

#define offsetof(TYPE, MEMBER) ((size_t) &(((TYPE *)0)->MEMBER))
//#define OffsetOf(TYPE, MEMBER) (&(((TYPE *)0)->MEMBER))

#define container_of(ptr, type, member) ({ \
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
(type *)( (char *)__mptr - offsetof(type,member) );})

typedef struct abc {
char a;
int b;
char c;
} ABC;

int main(void) {
printf("sizeof(ABC) = %zu\n", sizeof(ABC));
printf("offsetof(ABC, a) = %zu\n", offsetof(ABC, a));
printf("offsetof(ABC, b) = %zu\n", offsetof(ABC, b));
printf("offsetof(ABC, c) = %zu\n", offsetof(ABC, c));

ABC abc = {'a', 42, 'c'};
const int *b_ptr = &abc.b;
ABC *abc_ptr = container_of(b_ptr, ABC, b);
printf("address: %p\t%p\n", abc_ptr, &abc);

return 0;
}
102 changes: 102 additions & 0 deletions 11-struct/sds-202412.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
// Created by hengxin on 12/11/24.
// sds.h: https://github.com/redis/redis/blob/unstable/src/sds.h
// sds.c: https://github.com/redis/redis/blob/unstable/src/sds.c

/* SDSLib 2.0 -- A C dynamic strings library
*
* Copyright (c) 2006-Present, Redis Ltd.
* All rights reserved.
*
* Licensed under your choice of the Redis Source Available License 2.0
* (RSALv2) or the Server Side Public License v1 (SSPLv1).
*/

#include <stdio.h>
#include <ctype.h>
#include <stdint.h>

typedef char *sds;

struct __attribute__ ((__packed__)) sdshdr5 {
unsigned char flags; /* 3 lsb of type, and 5 msb of string length */
char buf[];
};

struct __attribute__ ((__packed__)) sdshdr8 {
uint8_t len; /* used */
uint8_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};

struct __attribute__ ((__packed__)) sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};

struct unpacked_sdshdr16 {
uint16_t len; /* used */
uint16_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};

struct __attribute__ ((__packed__)) sdshdr32 {
uint32_t len; /* used */
uint32_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};

struct __attribute__ ((__packed__)) sdshdr64 {
uint64_t len; /* used */
uint64_t alloc; /* excluding the header and null terminator */
unsigned char flags; /* 3 lsb of type, 5 unused bits */
char buf[];
};

#define SDS_TYPE_5 0
#define SDS_TYPE_8 1
#define SDS_TYPE_16 2
#define SDS_TYPE_32 3
#define SDS_TYPE_64 4
#define SDS_TYPE_MASK 7
#define SDS_TYPE_BITS 3
#define SDS_HDR(T, s) ((struct sdshdr##T *)((s)-(sizeof(struct sdshdr##T))))
#define SDS_TYPE_5_LEN(f) ((f)>>SDS_TYPE_BITS)

static inline int sdsHdrSize(char type) {
switch (type & SDS_TYPE_MASK) {
case SDS_TYPE_5:return sizeof(struct sdshdr5);
case SDS_TYPE_8:return sizeof(struct sdshdr8);
case SDS_TYPE_16:return sizeof(struct sdshdr16);
case SDS_TYPE_32:return sizeof(struct sdshdr32);
case SDS_TYPE_64:return sizeof(struct sdshdr64);
}
return 0;
}

static inline size_t sdslen(const sds s) {
unsigned char flags = s[-1];
switch (flags & SDS_TYPE_MASK) {
case SDS_TYPE_5:return SDS_TYPE_5_LEN(flags);
case SDS_TYPE_8:return SDS_HDR(8, s)->len;
case SDS_TYPE_16:return SDS_HDR(16, s)->len;
case SDS_TYPE_32:return SDS_HDR(32, s)->len;
case SDS_TYPE_64:return SDS_HDR(64, s)->len;
}
return 0;
}

int main(void) {
// test sdsHdrSize
printf("%d\n", sdsHdrSize(SDS_TYPE_5));
printf("%d\n", sdsHdrSize(SDS_TYPE_8));
printf("%d\n", sdsHdrSize(SDS_TYPE_16));
printf("%zu\n", sizeof(struct unpacked_sdshdr16));
printf("%d\n", sdsHdrSize(SDS_TYPE_32));
printf("%d\n", sdsHdrSize(SDS_TYPE_64));
return 0;
}
Loading

0 comments on commit e81ec01

Please sign in to comment.