8-1 结构体【内存占用分析】
include/io_utils.h
#ifndef BASICC_IO_UTILS_IO_UTILS_H_
#define BASICC_IO_UTILS_IO_UTILS_H_
#include <stdio.h>
#include <limits.h>
void PrintBinary(unsigned int value);
#define PRINT_METADATA
#ifdef PRINT_METADATA
# define PRINTLNF(format, ...) printf("("__FILE__":%d) %s: "format"\n", __LINE__, __FUNCTION__ , ##__VA_ARGS__)
#else
# define PRINTLNF(format, ...) printf(format"\n", ##__VA_ARGS__)
#endif
#define PRINT_CHAR(char_value) PRINTLNF(#char_value": %c", char_value)
#define PRINT_WCHAR(char_value) PRINTLNF(#char_value": %lc", char_value)
#define PRINT_INT(int_value) PRINTLNF(#int_value": %d", int_value)
#define PRINT_LONG(long_value) PRINTLNF(#long_value": %ld", long_value)
#define PRINT_LLONG(long_value) PRINTLNF(#long_value": %lld", long_value)
#define PRINT_BINARY(int_value) PrintBinary((unsigned int) int_value);
#define PRINT_HEX(int_value) PRINTLNF(#int_value": %#x", int_value)
#define PRINT_BOOL(bool_value) PRINTLNF(#bool_value": %s", bool_value ? "true" : "false")
#define PRINT_DOUBLE(double_value) PRINTLNF(#double_value": %g", double_value)
#define PRINT_STRING(string_value) PRINTLNF(#string_value": %s", string_value)
#define PRINT_ARRAY(format, array, length) \
{ int array_index; \
for (array_index = 0; array_index < length; ++array_index) { \
printf(format, array[array_index]); \
};\
printf("\n"); }
#define PRINT_INT_ARRAY_LN(array, length) \
{ int i; \
for (i = 0; i < length; ++i) { \
PRINTLNF(#array"[%d]: %d", i, array[i]); \
}}
#define PRINT_INT_ARRAY(array, length) PRINT_ARRAY("%d, ", array, length)
#define PRINT_CHAR_ARRAY(array, length) PRINT_ARRAY("%c, ", array, length)
#define PRINT_DOUBLE_ARRAY(array, length) PRINT_ARRAY("%g, ", array, length)
#endif //BASICC_IO_UTILS_IO_UTILS_H_
01.struct.c
#include <stdio.h>
#include <io_utils.h>
int main() {
/*
* struct <结构体名> {
* <成员类型> <成员名>;
* ...
* } <结构体变量>;
*/
typedef struct Company {
char *name;
char *id;
char *location;
} Company;
typedef struct Person {
char *name;
int age;
char *id;
Company *company;
Company company2;
struct {
int extra;
char *extra_str;
} extra_value;
struct Person *partner;
} Person;
struct Company company = {.name="imooc", .id="1212121"};
struct Person person = {.name="bennyhuo", .id="12113322222", .company=&company,
.company2={.name="imooc", .id="32323232"}
};
PRINT_INT(person.age);
person.age = 30;
//person.company->name
//person.extra_value.extra
PRINT_HEX(&person);
Person *person_ptr = &person;
puts(person_ptr->name);
PRINT_INT(sizeof(Person));
PRINT_INT(sizeof(person));
struct {
char *name;
int age;
char *id;
} anonymous_person;
Person person1 = {.name = "andy", .age = 20};
PRINT_INT(person1.age);
return 0;
}
8-2 结构体的内存对齐【内存占用优化】
02.memory_align.c
#include <io_utils.h>
#include <stddef.h>
//#pragma pack(2)
int main() {
typedef struct Person {
char *name;
int age;
char *id;
} Person;
struct Person person = {.name="bennyhuo", .id="12113322222"};
PRINT_INT(person.age);
person.age = 30;
typedef struct {
char a; // 1
char b; // 1
// __attribute((aligned(2))) int c; // 4 gcc only
// _Alignas(8) int c; // 4 c11
int c;
short d; // 2
double e; // 8
} Align;
typedef struct {
char a; // 1
char b; // 1
short d; // 2
int c; // 4
double e; // 8
} OptimizedAlign;
Align align = {'a', 'b', 3, 4, 5.0};
//PRINT_INT(_Alignof(align.c));
PRINT_INT(offsetof(Align, e));
return 0;
}
8-3 联合体【使用场景分析】
03.union.c
#include <io_utils.h>
#define OP_PRINT_INT 0
#define OP_PRINT_DOUBLE 1
#define OP_PRINT_STRING 2
typedef union Operand {
int int_operand; // 4
double double_operand; // 8
char *string_operand; // 8
} Operand;
typedef struct Instruction {
int operator;
Operand operand;
} Instruction;
void Process(Instruction *instruction) {
switch (instruction->operator) {
case OP_PRINT_INT: PRINT_INT(instruction->operand.int_operand);
break;
case OP_PRINT_DOUBLE: PRINT_DOUBLE(instruction->operand.double_operand);
break;
case OP_PRINT_STRING: puts(instruction->operand.string_operand);
break;
default:
fprintf(stderr, "Unsupported operator: %d\n", instruction->operator);
}
}
int main() {
PRINT_INT(sizeof(Operand));
Operand operand; // = {.int_operand=5, .double_operand=2.0};
operand.int_operand = 5;
operand.double_operand = 2.0;
PRINT_INT(operand.int_operand);
PRINT_DOUBLE(operand.double_operand);
Instruction instruction = {
.operator = OP_PRINT_STRING,
.operand = {
.string_operand = "Hello World!"
}
};
Process(&instruction);
return 0;
}
8-4 枚举【多语言对比】
04.enum.c
#include <io_utils.h>
typedef enum FileFormat {
PNG, JPEG = 10, BMP = 20, UNKNOWN
} FileFormat;
FileFormat GuessFormat(char *file_path) {
FILE *file = fopen(file_path, "rb");
FileFormat file_format = UNKNOWN;
if (file) {
char buffer[8] = {0};
size_t bytes_count = fread(buffer, 1, 8, file);
if (bytes_count == 8) {
// bmp: 42 4D
// png: 89 50 4E 47 0D 0A 1A 0A
// jpeg: FF D8 FF E0
if (*((short *) buffer) == 0x4D42) {
file_format = BMP;
} else if(*((long long *) buffer) == 0x0A1A0A0D474E5089) {
file_format = PNG;
} else if(*((int *) buffer) == 0xE0FFD8FF) {
file_format = JPEG;
}
}
fclose(file);
}
return file_format;
}
int main() {
FileFormat file_format = PNG;
FileFormat file_format_1 = 1;
PRINT_INT(GuessFormat("images/c.png"));
PRINT_INT(GuessFormat("images/c.jpeg"));
PRINT_INT(GuessFormat("images/c.bmp"));
PRINT_INT(GuessFormat("images/c.webp"));
return 0;
}
8-5 案例:判断字节序
05.byte_order.c
#include <io_utils.h>
int IsBigEndian() {
union {
char c[2];
short s;
} value = {.s=0x100};
return value.c[0] == 1;
}
int IsBigEndian2() {
short s = 0x100;
char *p = (char *)&s;
return p[0] == 1;
}
int ToggleEndian(int original) {
union {
char c[4];
int i;
} value = {.i=original};
char temp = value.c[0];
value.c[0] = value.c[3];
value.c[3] = temp;
temp = value.c[1];
value.c[1] = value.c[2];
value.c[2] = temp;
return value.i;
}
int ToggleEndian2(int original) {
char *p = (char *)&original;
char temp = p[0];
p[0] = p[3];
p[3] = temp;
temp = p[1];
p[1] = p[2];
p[2] = temp;
return original;
}
int main() {
PRINT_INT(IsBigEndian());
int original = 0x12345678;
PRINT_HEX(ToggleEndian(original));
return 0;
}
8-6 案例:单链表的基本实现
06.linked_list.c
#include <io_utils.h>
#include <stdlib.h>
typedef struct ListNode {
int value;
struct ListNode *next;
} ListNode;
ListNode *CreateNode(int value) {
ListNode *node = malloc(sizeof(ListNode));
if (!node) exit(1);
node->value = value;
node->next = NULL;
return node;
}
void DestroyNode(ListNode **node_ptr) {
(*node_ptr)->next = NULL;
free(*node_ptr);
*node_ptr = NULL;
}
ListNode *CreateList(int array[], int length) {
if (length <= 0) return NULL;
ListNode *head = CreateNode(array[0]);
ListNode *current = head;
for (int i = 1; i < length; ++i) {
current->next = CreateNode(array[i]);
current = current->next;
}
return head;
}
void DestroyList(ListNode **head) {
if (!head || !(*head)) return;
ListNode *current = *head;
while (current) {
ListNode *to_be_destroy = current;
current = current->next;
DestroyNode(&to_be_destroy);
}
*head = NULL;
}
void InsertNode(ListNode **head, int value, int index) {
if (!head || index < 0) return;
ListNode *new_node = CreateNode(value);
if (index == 0) {
new_node->next = *head;
*head = new_node;
} else {
if (!(*head)) {
*head = CreateNode(0);
}
ListNode *current = *head;
while (index > 1) {
if (!current->next) {
current->next = CreateNode(0);
}
current = current->next;
index--;
}
new_node->next = current->next;
current->next = new_node;
}
}
ListNode *FindNode(ListNode *head, int value) {
while (head && head->value != value) {
head = head->next;
}
return head;
}
void DeleteNode(ListNode **head, int value) {
printf("Delete: %d\n", value);
if (!head || !(*head)) return;
if ((*head)->value == value) {
ListNode *new_head = (*head)->next;
DestroyNode(head);
*head = new_head;
return;
}
ListNode *current_node = *head;
while (current_node->next && current_node->next->value != value) {
current_node = current_node->next;
}
if (current_node->next) {
ListNode *node_to_delete = current_node->next;
current_node->next = current_node->next->next;
DestroyNode(&node_to_delete);
}
}
void PrintList(ListNode *head) {
while (head) {
printf("%d, ", head->value);
head = head->next;
}
printf("\n");
}
int main() {
int array[] = {0, 1, 2, 3, 4};
ListNode *head = CreateList(array, 5);
PrintList(head);
InsertNode(&head, 100, 3);
InsertNode(&head, 200, 0);
InsertNode(&head, 300, 9);
InsertNode(&head, 400, 10);
PrintList(head);
DestroyList(&head);
PRINT_HEX(head);
InsertNode(&head, 10, 0);
PrintList(head);
DestroyList(&head);
InsertNode(&head, 10, 10);
PrintList(head);
DestroyList(&head);
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.17)
get_filename_component(ProjectId ${CMAKE_CURRENT_SOURCE_DIR} NAME)
string(REPLACE " " "_" ProjectId ${ProjectId})
project(${ProjectId} C)
set(CMAKE_C_STANDARD 11)
include_directories("include")
file(GLOB files "${CMAKE_CURRENT_SOURCE_DIR}/*.c")
foreach(file ${files})
get_filename_component(name ${file} NAME)
add_executable(${name} ${file})
endforeach()