为什么这个.c文件#include本身?

vsimple.c

#define USIZE 8
#include "vsimple.c"
#undef USIZE

#define USIZE 16
#include "vsimple.c"
#undef USIZE

#define USIZE 32
#include "vsimple.c"
#undef USIZE

#define USIZE 64
#include "vsimple.c"
#undef USIZE

推荐答案

该文件包括其自身,因此可以使用相同的源代码来为宏USIZE的特定值生成4组不同的函数.

#include条指令实际上包含在#ifndef中,这将递归限制在单个级别:

#ifndef USIZE

// common definitions
...
//

#define VSENC vsenc
#define VSDEC vsdec

#define USIZE 8
#include "vsimple.c"
#undef USIZE

#define USIZE 16
#include "vsimple.c"
#undef USIZE

#define USIZE 32
#include "vsimple.c"
#undef USIZE

#define USIZE 64
#include "vsimple.c"
#undef USIZE

#else // defined(USIZE)

// macro expanded size specific functions using token pasting

...

#define uint_t TEMPLATE3(uint, USIZE, _t)

unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) {
   ...
}

unsigned char *TEMPLATE2(VSDEC, USIZE)(unsigned char *__restrict ip, size_t n, uint_t *__restrict op) {
   ...
}

#endif

本模块中定义的函数包括

// vsencNN: compress array with n unsigned (NN bits in[n]) values to the buffer out. Return value = end of compressed output buffer out
unsigned char *vsenc8( unsigned char  *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsenc16(unsigned short *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsenc32(unsigned       *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsenc64(uint64_t       *__restrict in, size_t n, unsigned char  *__restrict out);

// vsdecNN: decompress buffer into an array of n unsigned values. Return value = end of compressed input buffer in
unsigned char *vsdec8( unsigned char  *__restrict in, size_t n, unsigned char  *__restrict out);
unsigned char *vsdec16(unsigned char  *__restrict in, size_t n, unsigned short *__restrict out);
unsigned char *vsdec32(unsigned char  *__restrict in, size_t n, unsigned       *__restrict out);
unsigned char *vsdec64(unsigned char  *__restrict in, size_t n, uint64_t       *__restrict out);

它们都是从vsimple.c中的两个函数定义展开的:

unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) {
   ...
}

unsigned char *TEMPLATE2(VSDEC, USIZE)(unsigned char *__restrict ip, size_t n, uint_t *__restrict op) {
   ...
}

TEMPLATE2TEMPLATE3宏在conf.h中定义为

#define TEMPLATE2_(_x_, _y_) _x_##_y_
#define TEMPLATE2(_x_, _y_) TEMPLATE2_(_x_,_y_)

#define TEMPLATE3_(_x_,_y_,_z_) _x_##_y_##_z_
#define TEMPLATE3(_x_,_y_,_z_) TEMPLATE3_(_x_, _y_, _z_)

这些宏是通过令牌粘贴创建标识符的classic 预处理器构造.TEMPLATE2TEMPLATE2_通常称为GLUEXGLUE.

函数模板的开头是:

unsigned char *TEMPLATE2(VSENC, USIZE)(uint_t *__restrict in, size_t n, unsigned char *__restrict out) ...

它在第一个递归包含中被扩展为USIZE,定义为8:

unsigned char *vsenc8(uint8_t *__restrict in, size_t n, unsigned char *__restrict out) ...

第二个递归包含将USIZE定义为16,将模板扩展为:

unsigned char *vsenc16(uint16_t *__restrict in, size_t n, unsigned char *__restrict out) ...

另外两个包裹体定义了vsenc32vsenc64.

预处理源代码的这种用法在单独的文件中更为常见:一个用于包含所有公共定义(特别是宏)的实例化部分,另一个用于代码和数据模板的单独文件,该文件多次包含在不同的宏定义中.

一个很好的例子是在QuickJS中从atomopcode定义生成枚举、字符串和 struct array.

C++相关问答推荐

如何通过Zephyr(Devicetree)在PR Pico上设置UTE 1?

try 使用sigqueue函数将指向 struct 体的指针数据传递到信号处理程序,使用siginfo_t struct 体从一个进程传递到另一个进程

如何在C中只使用一个带双方括号([i][j])访问语法的malloc来分配动态大小的2d数组?

单指针和空参数列表之间的函数指针兼容性

有没有更简单的方法从用户那里获取数据类型来计算结果

C:scanf(%d&q;,...)输入只有一个减号

如何使用低级C++写出数值

ESP32在vTaskDelay上崩溃

X86/x64上的SIGSEGV,由于原始内存访问和C中的DS寄存器之间的冲突,在Linux上用TCC编译为JIT引擎

当输入负数时,排序算法存在问题

将uintptr_t添加到指针是否对称?

这个C程序在工作中途停止获取输入.我收到分段故障(核心转储).我还是不知道问题出在哪里

如何只获取字符串的第一个单词,然后将其与c中的另一个单词进行比较?

将变量或参数打包到 struct /联合中是否会带来意想不到的性能损失?

如何在不更改格式说明符的情况下同时支持双精度和长双精度?

将size_t分配给off_t会产生符号转换错误

memcmp 是否保证按顺序比较字节?

如何使用 VLA 语法使用 const 指针声明函数

使用邻接表创建图

将字节/字符序列写入标准输出的最简单形式