V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
iqoo
V2EX  ›  程序员

C++ 中固定长度的数组作为参数,编译器能越界检查吗

  •  
  •   iqoo · 2023-03-13 11:40:42 +08:00 · 2234 次点击
    这是一个创建于 624 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如下代码:

    void F(char x[10]) {
      char y[10];
      y[11] = 0;  // warning: array index 11 is past the end of the array
    
      x[11] = 0;
    }
    

    数组 y 越界访问时编译器会给出告警,但 x 却不会,因为编译器会忽略参数数组的长度,是否有方案可让编译器检查参数数组的长度?

    20 条回复    2023-03-13 23:24:45 +08:00
    Noicdi
        1
    Noicdi  
       2023-03-13 12:10:37 +08:00 via iPhone
    你把 y 修改正确,x 依旧保持错误,看看会不会有警告呢?
    我下意识的猜想是,按顺序警告
    Thymolblue
        2
    Thymolblue  
       2023-03-13 12:11:58 +08:00 via Android
    好像是你这个函数并不会把数组长度这个信息传进去。下面这样可以把数组的长度传进去。我的编译器是 MinGW 7.3.0
    template <typename T>
    void foo(T &t)
    {
    // 可以直接使用迭代器迭代整个数组
    for (auto &item: t)
    {
    item = 0;
    }
    t[11] = 0; // 传一个长度为 10 的数组这里会触发警告
    }
    Thymolblue
        3
    Thymolblue  
       2023-03-13 12:12:29 +08:00 via Android
    @Thymolblue 手机编辑排版乱了,见谅
    sosilver
        4
    sosilver  
       2023-03-13 12:12:54 +08:00 via Android
    函数参数是 T*,不是 T[N],试试传 reference
    geelaw
        5
    geelaw  
       2023-03-13 12:19:04 +08:00   ❤️ 9
    因为 C 的缘故,void foo(char x[10]) 和 void foo(char *x) 是一个意思。要传递数组引用而不是指针的话,应该 void foo(char (&x)[10])。
    VZXXBACQ
        6
    VZXXBACQ  
       2023-03-13 12:21:23 +08:00
    这种情况传递引用可解
    ALLROBOT
        7
    ALLROBOT  
       2023-03-13 12:25:29 +08:00
    @geelaw C++还有这种用法,写起来真是麻烦。。。

    请问一般开发建议用什么标准的 C++?虽然写起来是麻烦了点,但跑起来挺快的
    SMGdcAt4kPPQ
        8
    SMGdcAt4kPPQ  
       2023-03-13 12:33:27 +08:00 via Android
    用 std::array
    tyzandhr
        9
    tyzandhr  
       2023-03-13 12:34:00 +08:00 via Android
    为什么不用 span 呢?
    tool2d
        10
    tool2d  
       2023-03-13 12:36:57 +08:00
    还是用 std::vector 中括号操作符重载吧,重载在 debug 时候检测一下越界问题。

    这裸指针直接赋值,也太吓人了。
    yolee599
        11
    yolee599  
       2023-03-13 12:38:18 +08:00 via Android
    形参的 x[10] 完全等同于 *x ,指针不能确定数组大小
    yolee599
        12
    yolee599  
       2023-03-13 12:40:44 +08:00 via Android
    通常做法是再加一个形参来描述数组大小:
    void F(char *x, int len)
    leonshaw
        13
    leonshaw  
       2023-03-13 12:42:51 +08:00
    数组、std::array, std::span, std::vector 越界都是 UB ,告警是编译器的行为。
    tool2d
        14
    tool2d  
       2023-03-13 12:48:20 +08:00
    5 楼的代码很完美,但我总觉得看着好奇怪哦。

    nightwitch
        15
    nightwitch  
       2023-03-13 13:39:33 +08:00 via Android
    没什么特殊理由不要用 c style arr ,用 std::array 有效消除这种问题
    pipapa
        16
    pipapa  
       2023-03-13 14:08:04 +08:00
    有工具是可以扫描出来的,这种应该编码应该强制传长度参数进去
    rozbo
        17
    rozbo  
       2023-03-13 14:59:17 +08:00
    一个指针哪来的长度。。你得传数组的引用
    daveh
        18
    daveh  
       2023-03-13 15:39:06 +08:00 via iPhone
    试试用 CLion ,Inspections - Data flow analysis 里面有专门的数组越界检查,能查出问题。
    另外确实如前面有 V 友所说,函数入参并不是你想的那样,有可能你传入的数组够长,所以后一个编译器没法识别出问题。
    但 CLion 的 Data flow analysis ,会识别调用 F(x)的上下文,如果你传入数组 x 不够长,后一个也会报数组越界;如果 x 长度够则不报问题;如果没有 F 的函数调用,也不报问题。
    LuffyWong
        19
    LuffyWong  
       2023-03-13 17:44:24 +08:00
    最近刚好在读 the c++ programming language, 刚好 12.2.2 讲到了这个
    lzyliangzheyu
        20
    lzyliangzheyu  
       2023-03-13 23:24:45 +08:00 via Android
    数组传参会退化为指针,会丢失数组的大小信息,至少 C 是这样的,一般都是把数组当成指针传过去,至于数组的大小再单独一个参数传过去,至于 CPP 有没有什么更高级的特性就不清楚了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   6000 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 28ms · UTC 02:51 · PVG 10:51 · LAX 18:51 · JFK 21:51
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.