c - 如何改进这些大小写转换功能?

标签 c string optimization case-sensitive

作为学习练习,我的三个函数——ToggleCase、LowerCase 和 UpperCase——每个都需要一个指向 ASCII 字符字符串的指针,以空字符结尾;他们按预期工作。有没有更有效或更快的方法来完成这项任务?我是否违反了良好 C 编码的任何潜规则?我使用了宏,因为我认为它使代码看起来更好,并且比函数调用更有效。这是典型的还是矫枉过正?

请随意挑剔和批评代码(但一定要友善)。

case_conversion.h

#define CASE_FLAG 32
#define a_z(c) (c >= 'a' && c <= 'z')
#define A_Z(c) (c >= 'A' && c <= 'Z')

void ToggleCase(char* c);
void LowerCase(char* c);
void UpperCase(char* c);

case_conversion.c

#include "case_conversion.h"

void ToggleCase(char* c)
{
 while (*c)
 {
  *c ^= a_z(*c) || A_Z(*c) ? CASE_FLAG : 0;
  c++;
 }
}
void LowerCase(char* c)
{
 while (*c)
 {
  *c ^= A_Z(*c) ? CASE_FLAG : 0;
  c++;
 }
}
void UpperCase(char* c)
{
 while (*c)
 {
  *c ^= a_z(*c) ? CASE_FLAG : 0;
  c++;
 }
}

最佳答案

我的最爱:

*c += (*c-'A'<26U)<<5; /* lowercase */
*c -= (*c-'a'<26U)<<5; /* uppercase */
*c ^= ((*c|32U)-'a'<26)<<5; /* toggle case */

由于您的目标是嵌入式系统,您应该学习如何消除不必要的代码膨胀、分支等。确定 ascii 字符是否按字母顺序排列的条件是 4 次比较/分支操作;我的是 1。我建议查找一些关于算术和位操作技巧的好资源。

注意:我更改了 *32<<5 的操作在发布我的答案之后,因为许多嵌入式系统编译器太差而无法为你做这件事。为好的编译器编写代码时,*32可能会更好地说明您的意图。

编辑:关于我的代码有太多编译器生成的隐式操作的指控,我认为这是完全错误的。这是任何半体面的编译器应该为第一行生成的伪 asm:

  1. 加载*c并对其进行零扩展或符号扩展以填充 int大小的字(取决于普通 char 是有符号还是无符号)。
  2. 使用无符号(非溢出陷阱)减去常量 26 sub指导。
  3. 如果未设置进位标志,则有条件地跳转到其余代码。
  4. 否则,将 32 添加到 *c 处的值.

步骤 2 和 3 可以在使用比较跳转操作而不是标志的体系结构上组合。我能看到任何显着的幕后成本突然出现的唯一方法是如果机器不能直接处理字符,或者如果它使用讨厌的(符号/幅度或补码)有符号值表示,在这种情况下转换为无符号将是不平凡的。据我所知,现代嵌入式架构都没有这些问题;它们大多与遗留大型机(在较小程度上与 DSP 隔离)。

如果有人担心糟糕的编译器实际上会为 <<5 执行算术运算,你可以试试:

if (*c-'A'<26U) *c+=32;

而不是我的代码。无论如何,这可能更简洁,但我通常喜欢避免语句,因此我可以将代码放入循环条件或类似函数的宏中。

编辑 2: 根据要求,第一行的无分支版本:

<罢工> *c += (64U-*c & *c-91U)>>(CHAR_BIT*sizeof(unsigned)-5);

*c += (64U-*c & *c-91U) >> CHAR_BIT*sizeof(unsigned)-1 << 5;

为了使其可靠地工作,c应该有类型 unsigned char *unsigned int应该严格大于 unsigned char .

关于c - 如何改进这些大小写转换功能?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3883993/

相关文章:

c - 将指针值放入数组中

c - 为什么两个元素从字符串(从 char 到 int)的转换不能相加?

java - Javac 的 StringBuilder 优化弊大于利吗?

android - 不同 Angular 表现同一张图片

c++ - 生成有向无环图的快速算法

ios - 如何优化我的代码以在不同的类中使用一种方法而不是多个相同的方法?

fork() 之前写入的内容在输出中出现两次

c - 如何尽可能调整函数的返回值(在 AS3 和 C 中)

c - 通过 GTK 或 GDK 直接在屏幕上绘图

字符串数组上的 Java 字符串正则表达式以捕获嵌套数据