gpt4 book ai didi

c - (GNU/BSD) libc 宏如何安全?

转载 作者:太空宇宙 更新时间:2023-11-03 23:50:27 25 4
gpt4 key购买 nike

在重新实现一些 libc 函数后(在我学校的“个人”图书馆项目 libft 中),我想到了将一些实现为宏的想法,如下所示:

#define ft_isalnum(c)  (ft_isalpha(c) || ft_isdigit(c))
#define ft_isalpha(c) (ft_isupper(c) || ft_islower(c))
#define ft_isascii(c) (((c) >= 0) && ((c) <= 0177))
#define ft_isdigit(c) (((c) >= '0') && ((c) <= '9'))
#define ft_islower(c) (((c) >= 'a') && ((c) <= 'z'))
#define ft_isprint(c) (((c) >= 0040) && ((c) <= 0176))
#define ft_isspace(c) ((((c) >= 0x09) && ((c) <= 0x0d)) || ((c) == 0x20))
#define ft_isupper(c) (((c) >= 'A') && ((c) <= 'Z'))

但是,我很快发现像ft_isspace(s[--len])这样的指令变坏了,因为 len 变量被递减了三次。所以我必须创建实际函数而不是宏。

我知道宏是不安全的。但我看到 is*(3) 字符测试的 GNU/BSD libc 实现是宏。 他们如何确保宏安全?

我不允许(在学校)使用我自己没有实现的功能(malloc(3)free(3) 和一些系统调用除外)例如 write(2)。我认为调用函数只是为了测试 ASCII 字符是相当低效的。

谢谢。

最佳答案

在这种特殊情况下,对于 ctype.h 中的函数,linux 和 BSD 都在一个数组中查找值,该数组包含一个位掩码,用于可以调用函数的所有有效值 - [0,255]。每个函数只是用它们的参数索引数组,并检查是否设置了您要测试的特定位。这就是他们只对参数求值一次的方式。

它可能看起来像这样:

#define C_ALPHA 0x01
#define C_NUM 0x02
...
int ctype_array[256] = { ..., /* offset for 'A' */C_ALPHA|C_PRINT|C_UPPER, ...};
#define isalnum(c) (ctype_array[(c)] & (C_ALPHA|C_NUM))

在更一般的情况下,对于所有宏,一个技巧是:

#define foo(x) do { int _x = (x); do_something_with(_x, twice(_x)); } while (0)

当然,这个结构不能返回任何东西(do-while 结构是这样的,当作为一个单独的语句放在一个没有括号的 if/for/while 语句中时,它不会中断)。有一些编译器扩展允许像这样的宏被安全地实现并返回一个值。

一般来说,我建议使用内联函数或只使用普通函数。函数调用开销在现代 CPU 上并没有那么高,在大型程序中,您甚至可以通过为代码浪费更少的缓存来在宏观层面上获得显着的加速。首先让您的代码正确无误,然后在衡量您的内联是否真的在做任何事情的同时考虑加快它的速度。

关于c - (GNU/BSD) libc 宏如何安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21120265/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com