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

推荐订阅源

Cloudbric
Cloudbric
Schneier on Security
Schneier on Security
V2EX - 技术
V2EX - 技术
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
O
OpenAI News
S
Security @ Cisco Blogs
Scott Helme
Scott Helme
Security Archives - TechRepublic
Security Archives - TechRepublic
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
WordPress大学
WordPress大学
云风的 BLOG
云风的 BLOG
T
Threatpost
Hacker News: Ask HN
Hacker News: Ask HN
Microsoft Azure Blog
Microsoft Azure Blog
Know Your Adversary
Know Your Adversary
博客园 - 三生石上(FineUI控件)
A
About on SuperTechFans
Forbes - Security
Forbes - Security
NISL@THU
NISL@THU
Security Latest
Security Latest
G
Google Developers Blog
D
Docker
T
Threat Research - Cisco Blogs
N
Netflix TechBlog - Medium
C
CERT Recently Published Vulnerability Notes
H
Help Net Security
B
Blog
Martin Fowler
Martin Fowler
N
News and Events Feed by Topic
Simon Willison's Weblog
Simon Willison's Weblog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
Lohrmann on Cybersecurity
Y
Y Combinator Blog
PCI Perspectives
PCI Perspectives
F
Fortinet All Blogs
MyScale Blog
MyScale Blog
Project Zero
Project Zero
爱范儿
爱范儿
Cisco Talos Blog
Cisco Talos Blog
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
人人都是产品经理
人人都是产品经理
V
Vulnerabilities – Threatpost
P
Proofpoint News Feed
Cyberwarzone
Cyberwarzone
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
TaoSecurity Blog
TaoSecurity Blog
N
News | PayPal Newsroom
Recorded Future
Recorded Future

博客园 - 喜欢Ⅰ

先避免毁灭性错误,再谈聪明决策 通往天堂的三个阶梯 人类随机数趣闻 - 即使人们会觉得它更随机,但实际上它更不随机 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 来判断越界, 当然这种做法前头已经说了, 不同平台兼容性上, 存在潜在问题, 不推荐.  

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