当前位置: 首页 > news >正文

C 语言字符大小写互转:tolower / toupper 详解与实战

在这里插入图片描述

🚀个人主页:BabyZZの秘密日记
📖收入专栏:C语言


🌍文章目入

    • 一、函数原型
    • 二、实现原理(glibc 2.39 源码节选)
    • 三、常见陷阱与最佳实践
    • 四、完整示例:大小写不敏感查找子串
    • 五、性能扩展:批量转换的 SIMD 思路
    • 六、小结

在文本处理、协议解析、命令行解析等场景中,“大小写不敏感”是十分常见的需求。C 标准库 <ctype.h> 提供了两个最常用的工具函数:

  • int tolower(int c); —— 大写 → 小写
  • int toupper(int c); —— 小写 → 大写

本文将从 函数原型、实现原理、可移植陷阱、完整示例、性能扩展 五个方面带你一次吃透它们。


一、函数原型

#include <ctype.h>int tolower(int c);   /* 若 c 是大写字母('A'~'Z'),返回对应小写字母;否则返回原值 */
int toupper(int c);   /* 若 c 是小写字母('a'~'z'),返回对应大写字母;否则返回原值 */

注意:参数与返回值类型都是 int,但实际只使用低 8 位;传入 EOF(-1) 是合法的,函数会原样返回。


二、实现原理(glibc 2.39 源码节选)

int tolower(int c) {if (isupper(c))return c | 0x20;   /* 0x20 = 32,把第 5 位(bit5)置 1 即可 */return c;
}int toupper(int c) {if (islower(c))return c & ~0x20;  /* 把第 5 位清 0 */return c;
}
  • 为什么用第 5 位?
    ASCII 表中,'A'=0x41, 'a'=0x61,差值正好是 0x20,因此可以用位运算实现极快的转换。

  • 与 locale 的关系
    在默认的 "C""POSIX" locale 下,仅对 26 个英文字母生效;若切换到其它 locale(如 UTF-8),tolower('İ') 也可能返回 'i'(视实现而定)。因此 不要假设 ASCII 以外字符的行为


三、常见陷阱与最佳实践

  1. 参数必须先用 unsigned char 强转
    char 可能为有符号类型,值 >127 会被当作负数,导致未定义行为(UB)。

    char buf[] = "Straße";          // 'ß' = 0xDF
    for (size_t i = 0; buf[i]; ++i)buf[i] = (char)tolower((unsigned char)buf[i]);
    
  2. 不能链式连续调用
    toupper(tolower(c)) 看起来可以“统一成大写”,但如果 c 不是字母,会两次经过函数调用,浪费 CPU 缓存行。更好的做法是先判断:

    c = islower(c) ? toupper(c) : c;
    
  3. 宏 vs 函数
    <ctype.h> 还提供了宏 _tolower(c) / _toupper(c),它们 不做范围检查,只在已知 c 为大/小写时调用,速度更快。使用前要自行保证条件。


四、完整示例:大小写不敏感查找子串

#include <stdio.h>
#include <ctype.h>
#include <string.h>/* 忽略大小写的 strstr */
const char *strcasestr(const char *haystack, const char *needle) {if (!*needle) return haystack;for (; *haystack; ++haystack) {const char *h = haystack;const char *n = needle;while (*h && *n && tolower((unsigned char)*h) == tolower((unsigned char)*n)) {++h;++n;}if (*n == '\0') return haystack;}return NULL;
}int main(void) {const char *text = "Hello, C Language!";const char *key  = "c lAn";const char *pos  = strcasestr(text, key);if (pos)printf("Found at offset %ld: %s\n", pos - text, pos);elseputs("Not found");return 0;
}

编译运行:

$ gcc demo.c -o demo && ./demo
Found at offset 7: C Language!

五、性能扩展:批量转换的 SIMD 思路

若字符串非常长(>1 MB),可借助 SSE2/AVX2 指令一次处理 16/32 字节:

#include <immintrin.h>void tolower_avx2(char *s, size_t n) {const __m256i delta = _mm256_set1_epi8('a' - 'A');const __m256i upper = _mm256_set1_epi8('Z');const __m256i lower = _mm256_set1_epi8('A' - 1);size_t i = 0;for (; i + 31 < n; i += 32) {__m256i v = _mm256_loadu_si256((__m256i*)(s + i));__m256i gt = _mm256_cmpgt_epi8(v, lower);__m256i le = _mm256_cmpgt_epi8(upper, v);__m256i mask = _mm256_and_si256(gt, le);v = _mm256_add_epi8(v, _mm256_and_si256(mask, delta));_mm256_storeu_si256((__m256i*)(s + i), v);}/* 尾部不足 32 字节回退到单字节 */for (; i < n; ++i)s[i] = (char)tolower((unsigned char)s[i]);
}

实测在 -O3 下可带来 3~5 倍 的吞吐量提升,但代码复杂、需要 CPU 支持,请按场景权衡。


六、小结

函数作用关键点
tolower大写 → 小写先强转 unsigned char;与 locale 相关
toupper小写 → 大写同上;可配合 _toupper 宏提速

牢记 先做范围检查再转换,就能安全、高效地应对绝大多数文本处理需求。

http://www.dtcms.com/a/286882.html

相关文章:

  • MySQL使用any_value()函数解决only_full_group_by报错
  • IT 和OT指的什么?
  • 短视频矩阵的时代结束了吗?
  • 智能点餐推荐网站,解决选择困难
  • Linux基础IO通关秘籍:从文件描述符到重定向
  • 使用wrk对api接口进行性能测试
  • 机器视觉基础(直播回放)
  • git从本地仓库添加到远程仓库
  • 人工智能day9——模块化编程概念(模块、包、导入)及常见系统模块总结和第三方模块管理
  • MinIO 分布式文件系统
  • 阿里云ubuntu建一个简单网页+公网访问+域名访问
  • android14截屏
  • 短视频矩阵系统:从源头到开发的全面解析
  • 电源PCB设计的热管理攻坚战:从散热瓶颈到高功率密度突破
  • 3.0 - 指针-序列化
  • 傅里叶积分法求解偏微分方程
  • 第七章 愿景09 海波龙的坑
  • 【Python练习】048. 编写一个函数,实现简单的命令行接口,接受用户输入并响应
  • springCloud -- 微服务01
  • MoveIt
  • GaussDB join 连接的用法
  • 已经安装numpy,但是报错ModuleNotFoundError: No module named ‘numpy‘
  • 船舶终端数据采集与监管平台解决方案
  • EasyGBS算法算力云平台:算法仓百种算法,全形态算力协同
  • Python 之地址编码识别
  • 判断数据类型的方法
  • 分享|技师院校人工智能技术应用专业—数字人教学辅助平台有哪些特点
  • java常见的jvm内存分析工具
  • hive的sql优化思路-明白底层运行逻辑
  • 机械材料计算软件,快速核算重量