c基础

##

  1. 数组不支持变量定义数组大小,如下:未初始化数组错误。只能通过编译时常量#define 定义
size_t maxlineLen = 128;
char line[maxlineLen] = {0};
  1. 为啥有puts没有gets?

    被废除了,不安全。可以使用fgets, getline这类限制大小。一般使用后者不保留\n

  2. 读写函数中有哪些外部分配,有哪些内部分配?

    内部分配的:getline

    外部分配的:fgets

  3. 一直strtok会发生什么?

    • 最后返回null
    • 原始字符串破坏了,替换为\0
  4. fork子进程分支如果没有exit会发生什么?是必须的嘛?

    是的,会发生未定义行为,且会进入父亲代码。

时间

CPU时间:程序占用CPU时间。clock_tlong毫秒级。

正常时间:

  • 微秒级:struct timevalgettimeofday()
  • 纳秒级:struct timespecclock_gettime()

  • 毫秒级:time_t , long; struct tm

场景:

  1. 时间戳转换为字符串?

    • ctime(time_t *) :固定格式,带换行。快速使用。
    • 如果要转为指定格式字符串,要先转为struct tm
  2. time_tstruct tm转换:

    • 时间戳转为tm结构:localtime() gmtime()UTC的
  3. tm转字符串:

    • strftime()
  4. 屏幕刷新频率?

    • 使用usleep实现,0.1s, 0.2秒感知用户输入

重载冗杂

sizeof并不是一个函数,而是一个操作符。

  • 操作数是变量:不必加括号。 sizeof *p 获取p指针指向对象的字节数
  • 操作数是类型:必须加括号。sizeof(int) *p。 这里含义是什么? 强制转换int型之后 sizeof?还是int长度乘以p? 实践:是后者。

Int main(){

chara = ‘5’;

int*p = &a;

int q = sizeof(int) * p;

printf(“%d”, q);

return0;

}

结构体

柔性数组必须作为结构体最后一个字段。

问题,redis ziplist 压缩列表希望柔性数组后面再来一个zlend末尾标记,这就会冲突!

typedef struct {
  unsigned int zlbytes;  // 压缩列表总字节数
  unsigned int zltail;   // 到最后一个节点的偏移量
  unsigned short zllen;  // 压缩列表中节点数
  unsigned char entries[]; // 节点数据(变长)
unsigned int zlend;
} ziplist;
解决:额外检测zlend字段,创建内存时候,加上zlend字节。但是结构不包含

向前声明!

  • 如果 A 里放 B*,只声明 struct B; 就够了
  • 如果 A 里放 B b;,就得先完整定义 struct B {}

两种写法

struct ConnectionListener;

typedef struct {
    int fd;
    struct ConnectionListener *listener;
    // 其他字段
} Connection;

typedef struct ConnectionListener {
    int port;
    char *bindAddr;
    Connection *conn;
} ConnectionListener;

typedef struct ConnectionListener;

typedef struct {
    int fd;
    ConnectionListener *listener;
    // 其他字段
} Connection;

struct ConnectionListener {
    int port;
    char *bindAddr;
    Connection *conn;
} ;

强制结构体/变量对齐。

场景:现在pool结构后面,要跟数据区域。但是整个内存要求8字节对齐,pool结构lock属性尺寸不能保证是8字节对齐的。

typedef struct {
    // meta
    uint32_t magic;
    uint32_t version;
    uint32_t cap;
    uint32_t used;
    
    // 
    FreeBlock freeListHead; // 空闲链表头

    //
    pthread_mutex_t lock; // 内存池锁

    // data

} Pool; 

__attribute__((aligned(8))) 是编译器的扩展语法,能够强制结构体/变量对齐。

这个叫编译器属性,不是C语言语法或者宏,一般我们通过宏展开添加#define ALIGN8 __attribute__((aligned(8)))

``attribute((aligned(8))) struct pool {};`

int x __attribute__((aligned(16)))

字符串

string类函数是原地修改,内部分配吗?

除了strdup内部会分配,其余不会主动malloc。

strtok, strcat都会原地修改dest

一些结构体内有char* 属性,什么时候该直接赋值,什么时候该dump:

基本上都要dump~

char* buf; c->buf = "aaaa";后者常量字符串是编译时候生成在只读段的,这就是正常的指针指向。

IO

snprintf 返回打印的字符数。

printf行缓冲行为。默认遇到\n或者缓冲区满才会刷新的标准输出。程序推出前会自动fflush(stdout)

下面代码, printf不会打印。因为行缓冲。


int main(int argc, char const *argv[])
{
    PoolContext ctx = {NULL,-1};
    pool_create(&ctx);
    printf("??");
    signal(SIGINT, sigintHandler); // CTRL+C
    void* ptr=  pool_alloc(16, &ctx);
    uint64_t* cp = (uint64_t*)ptr;
    *cp = 0XFFFFFFFFFFFFFFFF; // 测试写入
    // pool_free(ptr, &ctx);
    while (!stop) {
        sleep(1);
    }
    puts("stopped");
    pool_close(&ctx);
    pool_cover(&ctx);
    pool_destroy(&ctx);
    return 0;
}  

GLIB

GLIB文档

glib是跨平台的C工具库。相关地,glibc(GNU C)是linux的标准C库,linux运行基础。

C标准分为语法和实现。

  • C标准库:就是一组标准头文件,规定实现含义。

  • C运行库:各平台自己实现,并添加一些扩展。比如LINUX的glibc和MS的MSVCRT

glib有6个主要模块:

  • GObject:面向对象特性:继承、信号、属性等
  • GIO:IO抽象(文件、流、网络)
  • GLib:基础工具。高级数据结构、内存管理、字符串处理、时间等
  • GModule: 跨平台动态加载模块接口?
  • GThread: 跨平台线程API和线程池支持。
  • GMainLoop:事件循环机制。

GTree 平衡二叉搜索树

随机

整数:

int x = rand() % 100;         // 0~99

浮点:

double r = rand() / (double)RAND_MAX;          // [0, 1)
double r2 = 90.0 + r * 20.0;                   // [90.0, 110.0)

时间种子:

srand((unsigned(time(NULL))

随机字符:

char c = 'A' + rand() % 26;

布尔值:

bool b = rand() & 1;

ncurses

关于界面刷新和用户按键。

用户按键按下是有时长的, 如果1秒界面刷新,即意味着只有间隔1s才检测。 如果0.1秒,那就是每秒检测10次。显然会流畅很多。

安全信号处理

volatile sig_atomic_t stop = 0;

sig_atomic_t 类型表示 对于数据的访问不会被信号中断。

volatile 用于告知编译器,该变量的值可能会在编译器无法察觉的情况下被修改(例如,由信号处理程序修改)。防止编译器不必要优化,每次都从内存读取,不可使用缓存。

signal(SIGINT, sigintHandler); // CTRL+C
while (!stop) {

}
// 资源清理

指针加减

void*不允许加减,比如内存池通过offset + base指针定位需要转为char*

results matching ""

    No results matching ""