评估编译时间的恒定表达
我正在尝试编写一个预处理器宏 myprintf(x,...)
,该应该用 printf
来工作,但带有附加长度的指定器 w
。 w
的定义应该取决于操作系统,但在Linux上,它等效于 l
。
该代码正常工作,但是当 x
是恒定表达式时,我在评估表达式时遇到问题。例如,如果我
long int x = 13;
MYPRINTF("%wd\n", x);
在Linux系统上编写,我希望编译器在编译时间中将其转换为
long int x = 13;
printf("%ld\n", x);
查看装配代码,我可以说这不是发生的事情。
这是我正在运行的代码
#include <stdio.h>
#define SET_CHAR(ptr, cr) \
do \
{ \
*(ptr) = (cr); \
(ptr)++; \
} while (0)
#define SET_WORD_FMT(x) \
do \
{ \
SET_CHAR(x, 'l'); \
} while (0)
#define IS_FORMAT(c) ((c) == 'c' || (c) == 's' || (c) == 'd' || (c) == 'i' || (c) == 'o' || (c) == 'x' || (c) == 'X' || (c) == 'u' || (c) == 'f' || (c) == 'F' || (c) == 'e' || (c) == 'E' || (c) == 'a' || (c) == 'A' || (c) == 'g' || (c) == 'G' || (c) == 'n' || (c) == 'p')
#define MYPRINTF(x, ...) \
do \
{ \
char _str[512]; \
char * _strptr = _str; \
const char * _xptr = (x); \
while (*_xptr != '\0') \
{ \
if (*_xptr != '%') \
{ \
SET_CHAR(_strptr, *_xptr); \
_xptr++; \
continue; \
} \
\
SET_CHAR(_strptr, '%'); \
_xptr++; \
\
if (*_xptr == '%') \
{ \
SET_CHAR(_strptr, '%'); \
_xptr++; \
continue; \
} \
else while (!IS_FORMAT(*_xptr)) \
{ \
SET_CHAR(_strptr, *_xptr); \
_xptr++; \
} \
\
if (_strptr[-1] == 'w') \
{ \
_strptr--; \
SET_WORD_FMT(_strptr); \
} \
\
SET_CHAR(_strptr, *_xptr); \
_xptr++; \
} \
*_strptr = '\0'; \
printf(_str, __VA_ARGS__); \
} while (0)
int
main()
{
long int slx = 18273817628731872;
int x = 13;
int lx = 7128172;
long long int llx = 1928398172938791872;
MYPRINTF("hello %wd, %d, %ld, %% and %lld\n", slx, x, lx, llx);
}
,该代码是使用gcc 12.1.0与flags -o3 -march =本机
进行编译的。
是否可以在编译期间评估这一点?如果是这样,怎么样?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
不,这是不可能的。
例如,为62个字符串的恒定表达strlen编写非常非常内存消耗,并且您的编译器可以轻松地击中千兆字节的内存(主要是因为生成的预处理器代码需要很多)。为每种可能的情况编写恒定表达的字符串解析功能是不可行的,并且在实践中不可汇编。
如果您想要这样的功能,请移至其他编程语言或通过您的代码运行预处理器。例如,使用M4预处理器预处理您的代码。
glibc的额外长度指定符W,您可以重新定义
%d
转换并添加w
flag。No, it is not possible.
For example, writing of a constant-expression strlen for strings up to 62 is very memory consuming and your compiler can easily hit gigabytes of memory (mostly, because the generated preprocessor code takes so much). Writing a constant-expression string parsing function for every possible case is just not feasible and not compilable in practice.
If you want such functionality, move to a different programming language or run a preprocessor through your code. For example, preprocess your code with M4 preprocessor.
With glibc you can redefine
%d
conversion and addw
flag. https://www.gnu.org/software/libc/manual/html_node/Registering-New-Conversions.html这样做的方法是以OS依赖性方式定义具有长度说明符的单独宏。然后,您可以在需要的地方使用它。
请注意,这利用了连续的字符串文字的自动组合。
The way to do this is to define a separate macro with the length specifier in an OS dependent way. Then you can use that where you want.
Note that this takes advantage of automatic combination of consecutive string literals.