C 这个自定义toupper()函数是如何工作的?

C 这个自定义toupper()函数是如何工作的?,c,toupper,C,Toupper,我见过下面的程序使用自定义toupper()函数 #include <stdio.h> void my_toUpper(char* str, int index) { *(str + index) &= ~32; } int main() { char arr[] = "geeksquiz"; my_toUpper(arr, 0); my_toUpper(arr, 5); printf("%s", arr); return 0

我见过下面的程序使用自定义
toupper()
函数

#include <stdio.h> 
void my_toUpper(char* str, int index)
{
    *(str + index) &= ~32;
}
int main()
{
    char arr[] = "geeksquiz";
    my_toUpper(arr, 0);
    my_toUpper(arr, 5);
    printf("%s", arr);
    return 0;
}
#包括
void my_toUpper(char*str,int索引)
{
*(str+指数)&=~32;
}
int main()
{
char arr[]=“geeksquick”;
my_toUpper(arr,0);
my_toUpper(arr,5);
printf(“%s”,arr);
返回0;
}
这个函数究竟是如何工作的?我不明白背后的逻辑。如果有人能很容易地解释,那就好了

要将字母从小写转换为大写,需要从小写字母的ASCII值中减去
32

对于代表小写字母的ASCII值,减去32等于ANDIN
~32
。这就是我们正在做的事情

 *(str + index) &= ~32;
它从
str
中获取
索引
第th个成员的值,减去32(按位和使用
~32
,清除特定的位值),并将其存储回同一索引

FWIW,这是一种特殊情况,即“重置”特定位以获得实际减去32的结果。这种“减法”基于小写字母ASCII值的特定位表示在这里工作。正如评论中提到的,这不是一种一般的减法方法,因为这种“重置”逻辑对减法的任何值都不起作用

关于使用的

  • &=
    是按位和赋值的
  • ~
    不是按位的
注意:此自定义函数缺少对
str
中存在的(in)有效值的错误检查。您需要注意这一点。

接下来,要将字母从小写转换为大写,您需要从小写字母的ASCII值中减去
32

对于代表小写字母的ASCII值,减去32等于ANDIN
~32
。这就是我们正在做的事情

 *(str + index) &= ~32;
它从
str
中获取
索引
第th个成员的值,减去32(按位和使用
~32
,清除特定的位值),并将其存储回同一索引

FWIW,这是一种特殊情况,即“重置”特定位以获得实际减去32的结果。这种“减法”基于小写字母ASCII值的特定位表示在这里工作。正如评论中提到的,这不是一种一般的减法方法,因为这种“重置”逻辑对减法的任何值都不起作用

关于使用的

  • &=
    是按位和赋值的
  • ~
    不是按位的

注意:此自定义函数缺少对
str
中存在的(in)有效值的错误检查。您需要注意这一点。

要理解这一点,我们必须了解字母的ASCII表示形式。在base 2中最容易做到这一点

A  01000001        a  01100001
B  01000010        b  01100010
C  01000011        c  01100011
D  01000100        d  01100100
   ...                ...
X  01011000        x  01111000
Y  01011001        y  01111001
Z  01011010        z  01111010
请注意,大写字母均以
010
开头,小写字母均以
011
开头。请注意,对于同一字母的大写和小写版本,低位都是相同的

因此:要将小写字母转换为相应的大写字母,我们只需将
011
更改为
010
,或者换句话说,关闭
00100000

现在,关闭位的标准方法是对掩码进行逐位AND运算,在要关闭位的位置使用0,其他位置都使用1。所以我们想要的掩码是
11011111
。我们可以将其写成
0xdf
,但本例中的程序员选择通过编写
~32
来强调它是
00100000
的补充掩码。二进制中的32是
00100000

这项技术工作得很好,只是它会对非字母做一些奇怪的事情。例如,它将把
'{'
转换成
'['
(因为它们分别有ASCII码
011111011
0010110111
)。它将把星号
'*'
转换成新行
'\n'
00101010
转换成
00001010

在ASCII中,将大写转换为小写的另一种方法是减去32。这也将把
'a'
转换为
'a'
(97到65,十进制),但if也会将
'A'
转换为
'!'
。在这种情况下,按位AND技术实际上是有利的,因为它将
'A'
转换为
'A'
(这是转换为大写例程应该做的)

底线是,无论你是用~32和还是减去32,在一个适当安全的函数中,你还必须检查被转换的字符是否是正确的字母类型


此外,值得注意的是,该技术完全采用7位ASCII字符集,不适用于其他字符集的重音或非罗马字母,如ISO-8859或Unicode(EBCDIC将是另一回事)

要理解这一点,我们必须看看字母的ASCII表示法。最简单的方法是在基数2中

A  01000001        a  01100001
B  01000010        b  01100010
C  01000011        c  01100011
D  01000100        d  01100100
   ...                ...
X  01011000        x  01111000
Y  01011001        y  01111001
Z  01011010        z  01111010
请注意,大写字母均以
010
开头,小写字母均以
011
开头。请注意,对于同一字母的大写和小写版本,小写位均相同

因此:要将小写字母转换为相应的大写字母,我们只需将
011
更改为
010
,或者换句话说,关闭
00100000

现在,关闭一个位的标准方法是对一个掩码进行按位AND运算,其中0位于要关闭的位的位置,1位于其他位置。因此,我们想要的掩码是
11011111
。我们可以将其写成
0xdf
,但本例中的程序员选择强调它是
0的补充掩码0100000
通过写入