You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

inline函数参数会复制为新变量还是复用原输入变量?

typedef uint32_t StrTableKey_t;

typedef struct StrTableEntry_s
{
    char *string;
    StrTableKey_t keyhash, keyid;
    size_t usages;
} StrTableEntry_t;

typedef struct StrTable_s
{
    StrTableEntry_t *entries;
    StrTableKey_t count;
    StrTableKey_t capacity;
} StrTable_t;

inline bool StrTableBinarySearchUnsafe (const StrTable_t *table, StrTableKey_t keyid, size_t *output)
{
    size_t idxlow = 0, idxhigh = table->count - 1;

    while (idxlow <= idxhigh)
    {
        size_t idxmid = (idxlow + idxhigh) >> 1;

        if (table->entries[idxmid].keyid == keyid)
        {
            (*output) = idxmid;

            return true;
        }
        else if (table->entries[idxmid].keyid > keyid)
        {
            // 防止溢出bug
            if (idxmid == 0)
            {
                break;
            }

            idxhigh = idxmid - 1;
        }
        else
        {
            idxlow = idxmid + 1;
        }
    }

    return false;
}

char* StrTableGetValueByKey (const StrTable_t *table, StrTableKey_t keyid)
{
    size_t idx;

    if (table->count != 0 && StrTableBinarySearchUnsafe(table, keyid, &idx))
    {
        return table->entries[idx].string;
    }

    return NULL;
}

问题

  • StrTableBinarySearchUnsafe是项目中被多次调用的通用查找函数,负责在字符串表中按ID查找元素。
  • 我理解inline关键字会让编译器把这个函数的指令内联到调用它的StrTableGetValueByKey里,但有个疑问:传递的参数(table、keyid、&idx)会被复制成新变量,还是直接复用原函数里的变量?
  • 如果参数会被复制,StrTableGetValueByKey的栈空间占用几乎会翻倍;如果不复制,要是StrTableBinarySearchUnsafe修改了参数,就会影响到StrTableGetValueByKey里的变量。
  • 我分别在开启和关闭-O3优化的情况下做了测试,看起来参数是被复制的,或者编译器能智能判断哪些值需要复制,想确认这个结论是否正确。

编辑1

感谢指出我违反了私有标识符命名规则,原函数名_StrTableBinarySearchUnsafe已改为StrTableBinarySearchUnsafe。

我之前以为下划线开头(不含大写)可以用来标记翻译单元内的私有内容,现在改用后缀Unsafe来实现同样的标识目的。

解答

内联函数的参数处理没有固定规则,完全由编译器根据优化策略、函数逻辑和目标架构自主决定,结合你的代码和测试场景可以做如下具体分析:

  1. 针对你的代码参数:

    • table是const指针,函数内部仅做读操作,编译器完全可以直接复用StrTableGetValueByKey里的原指针,不需要复制——复制没有任何收益,反而增加额外开销。
    • keyid是值传递的基础类型(uint32_t),编译器大概率会直接把它放到寄存器里复用,甚至不会分配栈空间;就算在无优化(-O0)的情况下生成栈上副本,也是编译器为简化调试做的特殊处理,并非内联本身的强制要求。
    • &idx是指针参数,函数内部通过它修改idx的值——这里不存在"复制"的说法,传递的是idx的地址,内联后编译器会直接把对*output的操作映射到StrTableGetValueByKey里的idx变量,不需要额外中间变量。
  2. 关于你的测试结果:

    • 开启-O3时,编译器会做极致优化:所有可复用的变量都会直接复用,甚至可能把idx、keyid这类变量完全优化到寄存器中,连栈空间都不会分配。你看到的"复制"可能是反汇编时的表象(比如寄存器临时移动),本质并非栈上的复制操作。
    • 关闭优化(-O0)时,编译器为方便调试,会给每个函数的参数分配独立栈空间,哪怕内联后也会保留这种"伪函数调用"的栈布局,此时看起来像是参数被复制,但这是调试模式的特殊处理,不是内联的固有行为。
  3. 关于栈空间翻倍的担忧:
    完全没必要——内联函数的核心优势就是消除函数调用开销,同时让编译器有机会合并栈空间。就算在-O0下,栈空间的增加也只是因为编译器保留了调试用的参数副本,实际优化后的运行版本不会有这种问题。另外你的函数参数里没有大结构体,就算复制也不会带来明显的栈开销。

内容的提问来源于stack exchange,提问作者magg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:07:21