设为首页 加入收藏

TOP

C基础 那些年用过的奇巧淫技(二)
2017-10-12 12:45:25 】 浏览:4943
Tags:基础 那些 奇巧
ite_buffer, udp_address[0])); printf("offsetof(struct write_buffer, udp_address) = %d\n", offsetof(struct write_buffer, udp_address)); system("pause"); return 0; }

运行的结果如下

通过上面 可以知道 offsetof 其实计算的是结构体中字段的偏移量. 关于结构体的内存计算基础能力, 必须要掌握的. 洞悉内存结构很重要.

其实 offsetof 是 stddef.h 中定义的一个 宏 如下

#define offsetof(s,m) ((size_t)&(((s*)0)->m))

是不是很清爽. 就是这样, 没事简单的.

其实上面代码还隐含一个 关于 数组的 细节 . int a[10];  &a[0] == a == &a 地址是相同的.

 

4. 如何构造一个只能在堆上分配结构体?

//堆上 声明结构体
struct request_open {
    int id;
    int port;
    uintptr_t opaque;
    char host[];
};

就是上面那样, 加了[], 表示不完全类型. 只能在堆上分配内存. 使用方法.

struct request_open *open = malloc(sizeof(struct request_open) + sizeof(char) * 19);

这种结构一般在底层库会看见. 一些老的程序员喜欢这么写

//堆上 声明结构体
struct request_open {
    int id;
    int port;
    uintptr_t opaque;
    char host[0];
};

//堆上 声明结构体
struct request_open {
    int id;
    int port;
    uintptr_t opaque;
    char host[1];
};

因为老的编译器不支持 char host[]; 后面标准加了. 后来没改过习惯.

 

5. 如何构造一个在栈上初始化的指针变量

说的不好明白, 或者这么问, 下面定义的类型怎么解.

struct cstring_data {
    char* cstr;                                 //保存字符串的内容
    uint32_t hash;                                //字符串hash,如果是栈上的保存大小
    uint16_t type;                                //主要看 _INT_STRING_* 宏,默认0表示临时串
    uint16_t ref;                                //引用的个数, 在 type == 0时候才有用
};

typedef struct _cstring_buffer {
    struct cstring_data* str;
} cstring_buffer[1];                            //这个cstring_buffer是一个在栈上分配的的指针类型

上面也是底层库中会遇到一个技巧.

当声明cstring_buffer cb; 后.可以直接cb->str调用它,

当 cb 传入到 函数中. 仍然可以 cb->str. 可以理解为这个值是栈上的但是可以当指针变量用法去使用. 看下面也许好理解

typedef struct _jmp_buf { 
    int _jb[_JBLEN + 1]; 
} jmp_buf[1];

这个是 setjmp.h 里的一行定义,把一个 struct 定义成一个数组。

这样,在声明 jmp_buf 的时候,可以把数据分配到堆栈上。但是作为参数传递的时候则作为一个指针. 

扩展一下阅读理解可以看下面. 应该可以知道为什么这么搞.

//特殊的数组 声明结构体
#define _INT_STRING_ONSTACK        (4)                //标识 字符串分配在栈上
                                                //0 潜在 标识,这个字符串可以被回收,游离态

#define _INT_ONSTACK            (128)            //栈上内存大小

struct cstring_data {
    char* cstr;                                 //保存字符串的内容
    uint32_t hash;                                //字符串hash,如果是栈上的保存大小
    uint16_t type;                                //主要看 _INT_STRING_* 宏,默认0表示临时串
    uint16_t ref;                                //引用的个数, 在 type == 0时候才有用
};

typedef struct _cstring_buffer {
    struct cstring_data* str;
} cstring_buffer[1];                            //这个cstring_buffer是一个在栈上分配的的指针类型

/*
 * v : 是一个变量名
 *
 * 构建一个 分配在栈上的字符串.
 * 对于 cstring_buffer 临时串,都需要用这个 宏声明创建声明,
 * 之后可以用 CSTRING_CLOSE 关闭和销毁这个变量,防止这个变量变成临时串
 */
#define CSTRING_BUFFER(v) \
    char v##_cstring[_INT_ONSTACK] = { '\0' }; \
    struct cstring_data v##_cstring_data = { v##_cstring, 0, _INT_STRING_ONSTACK, 0 }; \
    cstring_buffer v; \
    v->str = &v##_cstring_data;

 

6. 那些年总有个align字段进行内存对齐

/*字节对齐的类型Align,为了优化CPU读取*/
typedef union {
    long        l_dummy;
    double      d_dummy;
    void        *p_dummy;
} Align;

/*标志大小,默认是4字节*/
#define MARK_SIZE       (4)
/*内存块头结点,双向链表结点size,filename,line都是为了调试添加的调试信息.prev和next是双向链表的核心*/
typedef struct {
    int         size;
    char        *filename;
    int         line;
    Header      *prev;
    Header      *next;
    unsigned char       mark[MARK_SIZE];
} HeaderStruct;

/*Align类型的字节大小*/
#define ALIGN_SIZE      (sizeof(Align))
/*这是个不错的技巧,求最小的n使得n*ALIGN_SIZE>=val成立,n,val,ALIGN_SIZE都属于自然数*/
#define reva lue_up_align(val)   ((val)
首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇LN : leetcode 242 Valid Anagram 下一篇gcc

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目