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

临时数组指针与局部/全局作用域:是否存在未定义行为?

全局与局部作用域临时数组的行为分析

测试代码

#include <iostream>
#include <cstdint>
#include <cstring>

struct bt_data {
uint8_t type;
uint8_t data_len;
const uint8_t* data;
};


static const char* devName="LSM6DSR_Sensor";


bt_data ad[] = {
    { .type = (0x01), .data_len = (sizeof((uint8_t []) { (0x02 | 0x04) })), .data = (const uint8_t *)(((uint8_t []) { (0x02 | 0x04) })), },
    { .type = (0x09), .data_len = (strlen(devName)-1), .data = (const uint8_t *)(devName), },
};

int main() {

uint8_t d1[] { (0x02 | 0x04) };

bt_data ad3[] = {
    { .type = (0x01), .data_len = 1, .data = d1, },
    { .type = (0x09), .data_len = 14, .data = (const uint8_t *)devName, },
};

bt_data ad2[] = {
    { .type = (0x01), .data_len = (sizeof((uint8_t []) { (0x02 | 0x04) })), .data = (const uint8_t *)(((uint8_t []) { (0x02 | 0x04) })), },
    { .type = (0x09), .data_len = (strlen(devName)-1), .data = (const uint8_t *)(devName), },
};

std::cout << "global: " << sizeof(ad) / sizeof(ad[0]) << " " << ad[1].data << std::endl;
std::cout << "local, extra: " << sizeof(ad3) / sizeof(ad3[0]) << " " << ad3[1].data << std::endl;
std::cout << "local temp: " << sizeof(ad2) / sizeof(ad2[0]) << " " << ad2[1].data << std::endl;

}

不同编译器输出

GCC 12.2.0 输出

Program returned: 0
global: 2 LSM6DSR_Sensor
local, extra: 2 LSM6DSR_Sensor
local temp: 1

GCC 14 输出

Program returned: 0
global: 2 LSM6DSR_Sensor
local, extra: 2 LSM6DSR_Sensor
local temp: 2 LSM6DSR_Sensor

Clang 提示

Clang编译器会对ad2发出警告,提示临时数组在表达式结束时销毁,导致后续指针访问悬空。

技术问题解答

1. 为什么全局作用域中的临时数组不会被销毁?

全局作用域的对象属于静态存储期,其生命周期从程序启动时开始,直到程序终止才结束。初始化全局数组ad时用到的临时复合数组,会被编译器分配到静态存储区域(如.rodata或.data段),不会在初始化表达式结束后被回收,因此ad中保存的指针始终指向有效内存。

而局部作用域(如main里的ad2)中的临时数组属于自动存储期,生命周期仅局限于创建它的完整表达式范围内——ad2初始化完成后,这些临时数组就会被销毁,此时ad2中的指针变为悬空指针,后续访问属于未定义行为。GCC 12.2.0中ad2元素数量显示为1,就是未定义行为导致的异常结果;GCC 14的输出看似正常,但这是编译器的非标准优化,依然不符合C++规范。

2. 该行为是否依赖特定C++标准?在C语言中(包括局部数组)情况是否有所不同?

  • C++标准层面:
    C标准明确规定,自动存储期的临时对象(包括临时数组)的生命周期通常在创建它的完整表达式结束时终止。静态存储期的临时对象(全局初始化时使用的)则与程序生命周期一致。C17之前,聚合初始化中临时对象的生命周期规则存在模糊地带,这也是GCC不同版本输出差异的原因。但无论哪个C++版本,局部作用域中用临时数组初始化指针的行为都是不安全的,属于未定义行为。

  • C语言中的差异:
    C99及以后支持复合字面量,但静态存储期对象的初始化器必须是常量表达式。静态区的复合字面量会被分配到静态存储区域,生命周期与程序一致;局部作用域的复合字面量属于自动存储期,生命周期在所在代码块结束时终止。和C类似,用局部复合字面量的指针初始化局部结构体数组时,同样会产生悬空指针问题,但C标准对临时对象的生命周期规则更简单直接,没有C中复杂的延长规则。

内容的提问来源于stack exchange,提问作者Maximilian Matthä

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:19:51