C-使用XOR位操作在Linux中的Toupper和Tolower功能



in Linux源代码

实施的topupper的实现如下

static inline unsigned char __tolower(unsigned char c)
{
        if (isupper(c))
            c -= 'A'-'a';
        return c;
}

 static inline unsigned char __toupper(unsigned char c)
 {
    if (islower(c))
            c -= 'a'-'A';
    return c;
 }

我可以按照下图使用xor(^)位操作。

如果我使用XOR操作,是否有潜在的错误?

 c -= 'A'-'a'; ----> c = c ^ 0x20 ;  //using xor to convert to lower case to upper case and vice versa

您很可能可以,但是很难看到这一点。

XOR:具有常数的字节值并不比添加(或减去)常数更快。并且它变为切换的好处(即toupper()tolower()可以是相同的代码)非常小,因为代码的量很小。

拆卸时,这两个功能:

int my_tolower1(int c)
{
  return c + 'a' - 'A';
}
int my_tolower2(int c)
{
  return c ^ ('a' - 'A');
}

几乎编译到同一件事,Modulo当然是添加与XOR:

my_tolower1(int):
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        addl    $32, %eax
        popq    %rbp
        ret
my_tolower2(int):
        pushq   %rbp
        movq    %rsp, %rbp
        movl    %edi, -4(%rbp)
        movl    -4(%rbp), %eax
        xorl    $32, %eax
        popq    %rbp
        ret

addlxorl指令都是三个字节,因此没有区别。我认为这些天它们都是最有趣的CPU中的单周期。

请注意,正如我在评论中所说的那样,通常您不应该四处走动,并假设您的C程序在可以做出这些假设的环境中运行。但是,Linux内核就是这样的环境。

在ASCII平台上,'a' - 'A'等于0x20,字母A-Z和A-Z具有连续的值,所有字母仅在六个最不重要的位置上有所不同,因此您可以使用c = c ^ 0x20。但是C标准并未指定字符编码,使此方法无法说明。

一个更便携式和自我日志的变体是:

c ^= 'A' ^ 'a';

(C标准也不要求字母A-Z和A-Z具有连续的值,因此Linux内核代码也不是严格可移植的。但是它的假设比XOR技巧更少。)

<) <。/div>

使用空间字符''而不是魔术编号0x20是更正确的。在这种情况下,功能也将对EBCDIC表有效。

这是一个指示的程序

#include <stdio.h>
char tolower(char c)
{
    return c ^ ' ';
}
char toupper(char c)
{
    return c ^ ' ';
}
int main( void )
{
    char s[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    puts( s );
    for (char *p = s; *p; ++p) *p = tolower(*p);
    puts( s );
    for (char *p = s; *p; ++p) *p = toupper(*p);
    puts( s );
}

程序输出是

ABCDEFGHIJKLMNOPQRSTUVWXYZ
abcdefghijklmnopqrstuvwxyz
ABCDEFGHIJKLMNOPQRSTUVWXYZ

当然,在调用功能之前,您应该检查参数是否是给定范围内的alpha字符。

最新更新