惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Help Net Security
Help Net Security
www.infosecurity-magazine.com
www.infosecurity-magazine.com
SecWiki News
SecWiki News
Webroot Blog
Webroot Blog
AI
AI
S
Secure Thoughts
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Cloudbric
Cloudbric
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
The Exploit Database - CXSecurity.com
Latest news
Latest news
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
Scott Helme
Scott Helme
S
Schneier on Security
H
Hacker News: Front Page
Forbes - Security
Forbes - Security
T
Troy Hunt's Blog
Know Your Adversary
Know Your Adversary
S
Security Affairs
V
Visual Studio Blog
Stack Overflow Blog
Stack Overflow Blog
博客园_首页
腾讯CDC
GbyAI
GbyAI
有赞技术团队
有赞技术团队
Last Week in AI
Last Week in AI
N
News and Events Feed by Topic
WordPress大学
WordPress大学
The Register - Security
The Register - Security
Engineering at Meta
Engineering at Meta
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
Recent Announcements
Recent Announcements
V
V2EX
S
Securelist
Security Archives - TechRepublic
Security Archives - TechRepublic
B
Blog RSS Feed
PCI Perspectives
PCI Perspectives
Security Latest
Security Latest
I
InfoQ
I
Intezer
L
LangChain Blog
雷峰网
雷峰网
NISL@THU
NISL@THU
博客园 - 【当耐特】
Microsoft Azure Blog
Microsoft Azure Blog
阮一峰的网络日志
阮一峰的网络日志

博客园 - 喜欢Ⅰ

先避免毁灭性错误,再谈聪明决策 通往天堂的三个阶梯 人类随机数趣闻 - 即使人们会觉得它更随机,但实际上它更不随机 C 里面如何使用链表 list 项目代码套路 墨菲定律 - 人类一种误判心理 消息队列, 一种取舍的选择 Redis Stream CORS 跨域请求一种后端适配解决方案 自我的智慧 市场教父 André Kostolany Exception Handling Considered Harmful MySQL CREATE TABLE Template 模板设计简单交流 atomic 原子自增工程案例 HTTP 尝试获取 Client IP 对炒股看法 吃饱年代 我是个怎样的人 格林童话之祖父和孙子 Linux 守护进程 智慧 ~ 引子 ~ 三则故事 交易人生 大道至简
字符串转整型
喜欢Ⅰ · 2022-03-08 · via 博客园 - 喜欢Ⅰ

🙏

奇奇怪怪编码 - https://www.emojiall.com/zh-hans/code/1F64F

正文

重新审视下这个编程开始时候必学问题, 整数字符串转成整数.

整数字符串意味着有效字符仅有 "+-0123456789". 

其中整数类型常见有 short, int , long, long long 等对吧. 大部分人会写成 string convert int. 

这里存在一个潜在模糊知识是, C 标准规定 sizeof(long long) >= sizeof (long) >= sizeof(int) >= sizeof(short).

但没有明说具体多大, 这就意味着不同平台实现上可以自由发挥. 例如 sizeof (long) 多数 linux 平台是 8, window 是 4.

所以这里不写那么复杂. 简单点尝试解决 string convet int32.

https://github.com/wangzhione/temp/blob/master/code/offer1/67_string_int.c#L17-L75

#include <stdio.h>
#include <limits.h>
#include <stddef.h>
#include <stdint.h>
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

/* describe : 

   写一个完整 string to int32_t
 */

#define NUMBER_SUCCESS  0    // 转换成功
#define NUMBER_INVALID -2    // 非法字符
#define NUMBER_BORDER  -3    // 数值越界

int str2int32(const char * str, int32_t * res) {
    if (str == NULL) {
        return NUMBER_INVALID;
    }

    if (*str == 0) {
        if (res) *res = 0;
        return NUMBER_SUCCESS;
    }

    // int32_t    int    Signed    32    4    -2,147,483,648    2,147,483,647
    // + - 1 字节, 后面 max size = 10
    // 如果 max size = 10, 那么 max size = 9 的时候最大值为 2,147,483,64

    int32_t num = 0;
    bool minus = false; // 标识负数
    if (*str == '+' || *str == '-') {
        minus = *str++ == '-';
    }

    char c;
    int count = 0;
    while (++count < 10 && (c = *str++) != 0) {
        if (c >= '0' && c <= '9') {
            // 合理字符
            num = 10 * num + c - '0';
        } else {
            return NUMBER_INVALID;
        }
    }
    if (c != 0) {
        if (num > 214748364) {
            // size = 9 时候最大值
            return NUMBER_BORDER;
        }
        c = *str++;
        if (*str != 0) {
            // size > 10 越界
            return NUMBER_BORDER;
        }
        if ((c >= '0' && c <= '7') || (c == '8' && minus)) {
            if (c == '8') {
                if (res) *res = -2147483648;
                return NUMBER_SUCCESS;
            }
            num = 10 * num + c - '0';
        } else {
            return NUMBER_BORDER;
        }
    }

    num = minus ? -num : num;
    if (res) *res = num;
    return NUMBER_SUCCESS;
}


// build:
// gcc -g -O3 -Wall -Wextra -Werror -o 67_string_int 67_string_int.c
//
int main(void) {
    int code;
    int32_t num;
    const char * str;

    num = 0;
    str = NULL;
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_INVALID && num == 0);

    num = 0;
    str = "-1";
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_SUCCESS && num == -1);

    num = 0;
    str = "1234A";
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_INVALID);

    num = 0;
    str = "2147483647";
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_SUCCESS && num == 2147483647);

    num = 0;
    str = "-2147483648";
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_SUCCESS && num == -2147483648);

    num = 0;
    str = "-2147483649";
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_BORDER);

    num = 0;
    str = "2147483648";
    code = str2int32(str, &num);
    printf("code = %d, str = %s, num = %d\n", code, str, num);
    assert(code == NUMBER_BORDER);

    exit(EXIT_SUCCESS);
}

整体代码分两部分实现 str2int32 和 assert 单元测试 . 单元测试怎么强调都不为过, 这是成为高手必经之路.

其中实现围绕核心思路是下面这些数学知识. 

int32_t    int    Signed    32    4    -2,147,483,648    2,147,483,647

实现层面没有借助 long 来判断越界, 当然这种做法前头已经说了, 不同平台兼容性上, 存在潜在问题, 不推荐.  

这类数据转换函数很多是跨学科, 对于普通工程师而言有点吃力, 感谢相关科学家或专业人士铸就了今天的基础.