【问题标题】:Change upper case to lower case and vice versa without using functions and if statements在不使用函数和 if 语句的情况下将大写更改为小写,反之亦然
【发布时间】:2015-03-19 07:55:15
【问题描述】:

我在 C 中有一个问题:

如果不使用 if 语句、函数以及不更改字母以外的字符,我不知道如何将大写字母更改为小写字母,反之亦然。

这个问题的解决方案对于资源有限的系统非常有用。

【问题讨论】:

  • 有许多可能的解决方案 - 到目前为止您尝试过什么?
  • “有限资源系统”如此有限,以至于连if语句都运行不了?
  • 我认为这是作业或面试问题。旨在考虑 ASCII 和十六进制表示以及位操作。
  • DrKoch - 在 C 语言基础课程中,该问题的解决方案被标记为可能对 µC 有用。

标签: c performance function if-statement


【解决方案1】:

你可以这样做:

c ^= ((c>='A' && c <= 'Z') || (c>='a' && c <= 'z')) << 5

...但我不确定对于资源有限的系统是否比使用 'if' 等更好。

【讨论】:

  • 您假设布尔表达式转换为整数 1 如果为真,则为 0 如果为假。这个假设正确吗?这不是未定义吗?
  • @chmike:是的,这是由 C 标准保证的。我还假设字符集是 ASCII,标准不保证这一点 - 但如果系统资源受限以至于无法承受if,那么假设特定字符集可能是合理的:-)
【解决方案2】:

因为 'A' 是 0x41 而 'a' 是 0x61,你可以对位 0x20 进行异或运算。

0x61 ^ 0x20 == 0x41  /* a -> A */
0x41 ^ 0x20 == 0x61  /* A -> a */

在一个完整字符串 char *s 的循环中(假设它只包含字母):

for (; *s; s++) *s ^= 0x20;


编辑

我们应该只将此应用于字母。 “A”是 0x41。 'Z' 是 0x5A,小写字符只是大写字符 + 0x20。

所以c &amp; 0xDF 始终是字符的大写版本。

混淆测试如下所示:

 for (; *s; s++) *s ^= ((*s & 0xDF) >= 0x41 && (*s & 0xDF) <= 0x5A) 
                    ? 0x20 : 0x00;

或等效且可读性稍强的:

 for (; *s; s++) *s ^= ((*s & 0xDF) >= 'A' && (*s & 0xDF) <='Z') 
                    ? 0x20 : 0x00;

【讨论】:

  • 很好的解释。但是,这些问题要求排除非字母。 ((c&gt;='A' &amp;&amp; c &lt;= 'Z') || (c&gt;='a' &amp;&amp; c &lt;= 'z')) 对于字母(A-z、a-z)计算为 1,对于其他字符计算为 0。将其考虑在内(即通过将 0x20 与它相乘)来完成答案。
【解决方案3】:

怎么样

void changecase (char * s)
{
    for (; *s; s++)
        *s ^= ((*s>='A') && (*s<='Z') || (*s>='a') && (*s<='z'))?32:0;
}

如果您不喜欢三元或比较运算符:

void changecase (char * s)
{
    for (; *s; s++)
        *s ~= (
               /* check top bits are 0100 or 0110 */
               ((*s & 0xE0 ^ 0x80) - 0x40) & 0x100) &&
               /* not codes 64 or 96 */
               (*s & 0x1f) &&
               /* first 26 from 64 onwards only */
               !(((*s && 0x1f) - 27) & 0x100)
              ) <<5;
}

【讨论】:

  • 可以提出三元等同于 if 语句的论点,但可以提出更强有力的论点,认为这个问题很愚蠢。 :)
  • @RetiredNinja 好的,所以我解决了这个问题并让它变得更加困难:-)
【解决方案4】:

最高效的方法是定义static char conversionTable = {0x00, 0x01, ...}。您只需将A 放在a 的ASCII 列表中,最后将z 放在Z 的位置。那么转换就变成了:

char original;
char converted;

converted = converionTable[original];

这将只花费 256 字节的内存,并且转换非常快,因为它只不过是一个索引表访问。

理论说明:如果我是对的,C 标准不保证使用 ASCII 作为字符表示。如果确实如此,问题仍然可以解决,但会变得更大。一张桌子不行。

【讨论】:

  • 我还没有看到像 tab = [1,2,3, ...] 这样的表格?我只看到过这样的表 = {1,2,3, ...}。是的 - 我使用的是 ASCII。
  • @Arlic 我搞错了,初始化数组当然是{1, 2, 3, ... }。您如何看待这个解决方案?
猜你喜欢
  • 2020-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-26
  • 2013-09-21
  • 2018-03-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多