NDK04_C:const、typedef、union共用体

本文深入探讨了NDK开发中的核心概念,包括const修饰符的使用规则,typedef的别名功能,以及union共用体的内存特性。通过具体示例,讲解了不同数据类型在内存中的表现形式和操作限制。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

NDK开发汇总

一 const

const char *, char const *, char * const,char const * const
const :常量 = final

//从右往左读
//P是一个指针 指向 const char类型
char str[] = "hello";
const char *p = str;
str[0] = 'c'; //正确
p[0] = 'c';   //错误 不能通过指针修改 const char

//可以修改指针指向的数据 
//意思就是 p 原来 指向david,
//不能修改david爱去天之道的属性,
//但是可以让p指向lance,lance不去天之道的。
p = "12345";

//性质和 const char * 一样
char const *p1;

//p2是一个const指针 指向char类型数据
char * const p2 = str;
p2[0] = 'd';  //正确
p2 = "12345"; //错误

//p3是一个const的指针变量 意味着不能修改它的指向
//同时指向一个 const char 类型 意味着不能修改它指向的字符
//集合了 const char * 与  char * const
char const* const p3 = str;

二 typedef

就是别名,类似java 代理
并没有创建新的数据类型,只是给现有类型创建了别名

typedef int _in;
typedef char * string;
typedef int(*PFI)(char *, char *);
typedef Tnode * Treeptr;
typedef struct Tnode {
	char *word;
	int count;
	Treeptr left;
	Treeptr right;
} BinaryTreeNode;

int fun(char *, char *) {
	return 0;

}

int test4() {
	_in a = 20;
	printf("%d\n", a);

	string str;
	str = (char *)"hello world";

	PFI fp;
	fp = fun;


	char * ch;

	ch = (char *)"hello world";

	BinaryTreeNode* node;
	node = (BinaryTreeNode *)malloc(sizeof(BinaryTreeNode));

	system("pause");
	return 0;
}

三 union 共用体

在相同的内存位置存储不同的数据类型
共用体占用的内存应足够存储共用体中最大的成员
成员共用一段内存,内存地址一致;最近定义的才有效

//占用4字节
union Data
{
	int i;
	short j;
}
union Data data;
data.i = 1;
//i的数据损坏
data.j = 1.1f;

Demo

union MyUnion {
	int a;
	char b;
	float c;
};

int test4() {
	MyUnion unio;

	unio.a = 10;
	unio.b = 'a';
	unio.c = 1.2f;
	printf("a: %#x, b: %#x, c: %#x\n", &unio.a, &unio.b, &unio.c);
	printf("a: %d, b: %c, c: %f\n", unio.a, unio.b, unio.c);

	system("pause");
	return 0;
}

运行结果:

a: 0x8ff660, b: 0x8ff660, c: 0x8ff660
a: 1067030938, b: ? c: 1.200000

四 Demo

lsn04

<think>嗯,用户给的这个错误信息看起来挺复杂的,首先得仔细看看里面有什么内容。看起来像是C++的标准库中的某个容器出了问题。错误信息提到了`std::__ndk1`,这可能和Android NDK有关,因为NDK的标准库实现通常会有这样的命名空间。 接下来,用户提到了`std::unordered_map<int, std::array<int, 2ul>>`,这应该是一个无序映射,键是整型,值是一个包含两个整型元素的数组。然后错误信息里出现了`operator[]`,这可能是在使用`operator[]`访问或插入元素时出现了问题。 可能的错误点有几个方面。首先,检查是否在使用`operator[]`时,键不存在于`unordered_map`中。因为`operator[]`在键不存在时会默认插入一个值初始化的元素,但如果值类型需要特定的构造参数,可能会导致问题。不过这里`std::array<int, 2ul>`的初始化应该是可行的,所以可能不是这个问题。 另一个可能是并发访问的问题,如果这个`unordered_map`在多线程环境下被同时读写,没有适当的同步机制,会导致未定义行为,比如崩溃。这时候需要检查代码中是否有锁或其他同步手段。 内存损坏也是可能的,比如越界访问或者使用已经释放的内存,影响到`unordered_map`的内部结构,导致在访问时崩溃。需要检查相关代码的内存管理部分,是否有潜在的漏洞。 另外,NDK的版本和标准库实现也可能有影响,不同版本可能有不同的行为或bug。可以尝试更新NDK版本或者使用不同的STL实现,比如c++_shared,看看问题是否依然存在。 用户提供的调用栈信息中有`Yolov8Pose_getRtspFrame`,这可能涉及到JNI代码。在JNI中处理C++对象时需要小心,比如是否正确地传递和转换指针,避免悬空指针或者类型转换错误。如果JNI层持有或访问了已经被释放的`unordered_map`实例,也会导致崩溃。 调试建议方面,可以尝试使用AddressSanitizer或Valgrind来检测内存问题。另外,在访问`unordered_map`之前添加日志,确认键是否存在,或者使用`at()`方法替代`operator[]`,因为`at()`在键不存在时会抛出异常,帮助定位问题。检查多线程同步,确保对`unordered_map`的访问是线程安全的。同时,确保JNI代码正确处理C++对象的生命周期,避免跨语言的资源管理问题。 总结起来,问题可能出在键不存在、并发访问、内存损坏或JNI处理不当这几个方面,需要逐一排查。</think>这个错误信息是典型的C++标准库容器操作崩溃,涉及Android NDK开发中的`std::unordered_map`使用问题。以下是逐步分析: --- ### **1. 核心问题定位** 代码段关键部分为: ```cpp std::unordered_map<int, std::array<int, 2ul>>::operator[] ``` 崩溃发生在通过`operator[]`访问或插入元素时。 --- ### **2. 常见原因分析** #### **(1) 键不存在时的隐式插入** - **问题**:`unordered_map::operator[]`会在键不存在时**自动插入默认值**。若值类型构造异常(如需要参数的构造函数),会导致未定义行为。 - **此处验证**:你的值类型是`std::array<int, 2>`,其默认构造是合法的(元素初始化为0)。因此**可能不是直接原因**。 #### **(2) 多线程并发访问** - **问题**:如果多个线程同时读写同一个`unordered_map`且**无同步机制**,会导致内部哈希表结构损坏。 - **验证方法**:检查是否在多线程环境中使用此map(如RTSP帧处理常涉及多线程)。 #### **(3) 内存越界或野指针** - **问题**:map所在内存可能被意外释放或覆盖(如JNI层对象生命周期管理错误)。 - **典型场景**:JNI代码中未正确持有或传递C++对象指针。 #### **(4) NDK标准库兼容性** - `std::__ndk1`命名空间表明使用了NDK的libc++实现。某些NDK版本存在STL容器实现的已知问题。 --- ### **3. 调试与修复步骤** #### **(1) 检查键是否存在性** 改用`find()`替代`operator[]`明确处理存在性: ```cpp auto it = my_map.find(key); if (it != my_map.end()) { // 安全访问 it->second } else { // 处理键不存在的情况 } ``` #### **(2) 添加线程同步** 如果是多线程问题: ```cpp std::mutex map_mutex; { std::lock_guard<std::mutex> lock(map_mutex); // 访问或修改map的代码 } ``` #### **(3) 内存安全性检查** - 使用`AddressSanitizer`检测内存错误: ```gradle android { defaultConfig { externalNativeBuild { cmake { arguments "-DANDROID_ARM_MODE=arm", "-DANDROID_STL=c++_shared" cppFlags "-fsanitize=address -fno-omit-frame-pointer" } } } } ``` #### **(4) JNI对象生命周期验证** 确保通过JNI传递的C++对象指针始终有效: - 使用`jlong`存储`native`指针时,需通过`NewGlobalRef`/`DeleteGlobalRef`管理对象生命周期。 #### **(5) 更新NDK版本** 尝试升级到最新NDK版本,或切换STL实现: ```gradle android { defaultConfig { externalNativeBuild { cmake { arguments "-DANDROID_STL=c++_shared" } } } } ``` --- ### **4. 关键日志建议** 在崩溃前插入调试日志: ```cpp __android_log_print(ANDROID_LOG_DEBUG, "TAG", "Accessing key=%d, map size=%zu", key, my_map.size()); ``` --- ### **总结** 问题可能由**多线程竞争访问`unordered_map`**或**JNI层对象生命周期管理错误**导致。优先检查线程同步和内存有效性,结合AddressSanitizer工具定位具体崩溃点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值