Просмотр исходного кода

refactor: 手动实现访问非对其指针

RyanCW 2 недель назад
Родитель
Сommit
c8d81400fb

+ 2 - 2
.vscode/settings.json

@@ -22,13 +22,13 @@
     ],
     "files.watcherExclude": {
         "**/test/fuzzer/corpus/**": true,
-        "./docs": true,
+        "./coverage": true,
         "./build": true,
         "./.xmake": true,
     },
     "files.exclude": {
         "**/test/fuzzer/corpus/**": true,
-        "./docs": true,
+        "./coverage": true,
         "./build": true,
         "./.xmake": true,
     },

+ 165 - 163
RyanJson/RyanJson.c

@@ -30,7 +30,7 @@ static int32_t RyanJsonSnprintf(char *buf, size_t size, const char *fmt, ...)
 {
 	static uint32_t jsonsnprintCount = 1;
 	jsonsnprintCount++;
-	if (jsonsnprintCount % RyanJsonRandRange(10, 500) == 0) { return 0; };
+	if (jsonsnprintCount % RyanJsonRandRange(10, 500) == 0) { return 0; }
 
 	va_list args;
 	va_start(args, fmt); // 每 500 次随机触发一次“失败”
@@ -163,18 +163,23 @@ static RyanJsonBool_e RyanJsonPrintValue(RyanJson_t pJson, RyanJsonPrintBuffer *
 static RyanJson_t RyanJsonCreateObjectAndKey(const char *key);
 static RyanJson_t RyanJsonCreateArrayAndKey(const char *key);
 
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wcast-align"
 static uint8_t *RyanJsonGetHiddePrt(RyanJson_t pJson)
 {
 	RyanJsonCheckAssert(NULL != pJson);
-	return *(uint8_t **)(RyanJsonGetPayloadPtr(pJson) + sizeof(void *));
+
+	// 用memcpy规避非对其警告
+	void *tmpPtr = NULL;
+	RyanJsonMemcpy((void *)&tmpPtr, (RyanJsonGetPayloadPtr(pJson) + RyanJsonAlign), sizeof(void *));
+	return (uint8_t *)tmpPtr;
 }
 static void RyanJsonSetHiddePrt(RyanJson_t pJson, uint8_t *hiddePrt)
 {
 	RyanJsonCheckAssert(NULL != pJson);
 	RyanJsonCheckAssert(NULL != hiddePrt);
-	*(uint8_t **)(RyanJsonGetPayloadPtr(pJson) + sizeof(void *)) = hiddePrt;
+
+	// 用memcpy规避非对其警告
+	void *tmpPtr = hiddePrt;
+	RyanJsonMemcpy((RyanJsonGetPayloadPtr(pJson) + RyanJsonAlign), (const void *)&tmpPtr, sizeof(void *));
 }
 
 /**
@@ -189,26 +194,43 @@ static uint8_t *RyanJsonGetHiddenPtrAt(RyanJson_t pJson, uint32_t index)
 	RyanJsonCheckAssert(NULL != pJson);
 	return (uint8_t *)(RyanJsonGetHiddePrt(pJson) + (index));
 }
-#pragma GCC diagnostic pop
 
 static void RyanJsonSetLenKey(RyanJson_t pJson, uint32_t value)
 {
 	RyanJsonCheckAssert(NULL != pJson);
+	uint8_t *buf = RyanJsonGetHiddenPtrAt(pJson, 0);
+	uint8_t len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson);
+	RyanJsonCheckAssert(len <= 4);
 
-	uint8_t *buf = (RyanJsonGetPayloadPtr(pJson) + sizeof(uint8_t));
-	RyanJsonMemcpy(buf, &value, 3);
+	RyanJsonMemcpy(buf, &value, len);
 }
 
 static uint32_t RyanJsonGetLenKey(RyanJson_t pJson)
 {
 	RyanJsonCheckAssert(NULL != pJson);
+	uint8_t *buf = RyanJsonGetHiddenPtrAt(pJson, 0);
+	uint8_t len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson);
+	RyanJsonCheckAssert(len <= 4);
 
-	uint8_t *buf = (RyanJsonGetPayloadPtr(pJson) + sizeof(uint8_t));
 	uint32_t value = 0;
-	RyanJsonMemcpy(&value, buf, 3);
+	RyanJsonMemcpy(&value, buf, len);
 	return value;
 }
 
+static void *RyanJsonGetValue(RyanJson_t pJson)
+{
+	RyanJsonCheckAssert(NULL != pJson);
+
+	uint32_t len = RyanJsonAlign;
+	if (RyanJsonIsKey(pJson) || RyanJsonIsString(pJson))
+	{
+		len += sizeof(void *);
+		// jsonLog(" keyLen: %d, keyLenField: %d, \r\n", RyanJsonGetLenKey(pJson), RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
+	}
+
+	return RyanJsonGetPayloadPtr(pJson) + len;
+}
+
 /**
  * @brief 用户不要使用,仅考虑realloc增大情况,没有考虑减少
  *
@@ -247,24 +269,6 @@ static uint8_t RyanJsonCalcLenBytes(uint32_t len)
 	return 3;
 }
 
-/**
- * @brief 提供内存钩子函数
- *
- * @param userMalloc
- * @param userFree
- * @param userRealloc 可以为NULL
- * @return RyanJsonBool_e
- */
-RyanJsonBool_e RyanJsonInitHooks(RyanJsonMalloc_t userMalloc, RyanJsonFree_t userFree, RyanJsonRealloc_t userRealloc)
-{
-	RyanJsonCheckReturnFalse(NULL != userMalloc && NULL != userFree);
-
-	jsonMalloc = userMalloc;
-	jsonFree = userFree;
-	jsonRealloc = userRealloc;
-	return RyanJsonTrue;
-}
-
 /**
  * @brief 安全的浮点数比较
  *
@@ -314,61 +318,32 @@ static RyanJsonBool_e printBufAppend(RyanJsonPrintBuffer *printfBuf, uint32_t ne
 	return RyanJsonTrue;
 }
 
-void *RyanJsonGetValue(RyanJson_t pJson)
-{
-	RyanJsonCheckReturnNull(NULL != pJson);
-
-	uint32_t len = 0;
-	if (RyanJsonIsKey(pJson) || RyanJsonIsString(pJson))
-	{
-		len += sizeof(void *); // 对齐偏移
-		len += sizeof(void *); // key和Str的指针
-		// jsonLog(" keyLen: %d, keyLenField: %d, \r\n", RyanJsonGetLenKey(pJson), RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
-	}
-	else if (RyanJsonIsObject(pJson) || RyanJsonIsArray(pJson))
-	{
-		len += sizeof(void *); // 对齐偏移
-	}
-	else
-	{
-		len += sizeof(uint8_t); // 对齐偏移
-	}
-
-	return RyanJsonGetPayloadPtr(pJson) + len;
-}
-
-char *RyanJsonGetKey(RyanJson_t pJson)
-{
-	RyanJsonCheckReturnNull(NULL != pJson);
-	return (char *)RyanJsonGetHiddenPtrAt(pJson, 0);
-}
-
-char *RyanJsonGetStringValue(RyanJson_t pJson)
+/**
+ * @brief 替换json对象节点
+ *
+ * @param prev
+ * @param oldItem
+ * @param newItem
+ * @return RyanJsonBool_e
+ */
+static RyanJsonBool_e RyanJsonReplaceNode(RyanJson_t prev, RyanJson_t oldItem, RyanJson_t newItem)
 {
-	RyanJsonCheckReturnNull(NULL != pJson);
-
-	uint32_t len = 0;
-	if (RyanJsonIsKey(pJson)) { len = RyanJsonGetLenKey(pJson) + 1U; }
+	RyanJsonCheckAssert(NULL != oldItem && NULL != newItem);
 
-	return (char *)RyanJsonGetHiddenPtrAt(pJson, len);
-}
+	// 链接前驱和新节点
+	if (NULL != prev) { prev->next = newItem; }
 
-int32_t RyanJsonGetIntValue(RyanJson_t pJson)
-{
-	RyanJsonCheckCodeNoReturn(NULL != pJson, { return 0; });
+	// 链接后继和新节点
+	if (NULL != oldItem->next) { newItem->next = oldItem->next; }
 
-	int32_t intValue;
-	RyanJsonMemcpy(&intValue, RyanJsonGetValue(pJson), sizeof(intValue));
-	return intValue;
+	oldItem->next = NULL;
+	return RyanJsonTrue;
 }
 
-double RyanJsonGetDoubleValue(RyanJson_t pJson)
+static RyanJsonBool_e RyanJsonChangeObjectValue(RyanJson_t pJson, RyanJson_t objValue)
 {
-	RyanJsonCheckCodeNoReturn(NULL != pJson, { return 0; });
-
-	double doubleValue;
-	RyanJsonMemcpy(&doubleValue, RyanJsonGetValue(pJson), sizeof(doubleValue));
-	return doubleValue;
+	RyanJsonMemcpy(RyanJsonGetValue(pJson), (void *)&objValue, sizeof(void *));
+	return RyanJsonTrue;
 }
 
 static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNew, const char *key, const char *strValue)
@@ -376,6 +351,7 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 	RyanJsonCheckAssert(NULL != pJson);
 
 	uint32_t keyLen = 0;      // key的长度
+	uint8_t keyLenField = 0;  // 记录key长度需要几个字节
 	uint32_t strValueLen = 0; // stringValue的长度
 
 	uint32_t mallocSize = 0;
@@ -384,7 +360,8 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 	if (NULL != key)
 	{
 		keyLen = RyanJsonStrlen(key);
-		mallocSize += keyLen + 1;
+		keyLenField = RyanJsonCalcLenBytes(keyLen);
+		mallocSize += keyLen + keyLenField + 1 + 1;
 
 #ifdef isEnableFuzzer
 		{
@@ -420,15 +397,17 @@ static RyanJsonBool_e RyanJsonChangeString(RyanJson_t pJson, RyanJsonBool_e isNe
 	if (NULL != key)
 	{
 		RyanJsonSetPayloadWhiteKeyByFlag(pJson, RyanJsonTrue);
+		RyanJsonSetPayloadEncodeKeyLenByFlag(pJson, keyLenField);
 		RyanJsonSetLenKey(pJson, keyLen);
 
-		jsonLog("keyLen: %d, \r\n", RyanJsonGetLenKey(pJson));
+		jsonLog(" keyLen: %d, keyLenField: %d, \r\n", RyanJsonGetLenKey(pJson), RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
 		if (0 != keyLen) { RyanJsonMemcpy(RyanJsonGetKey(pJson), key, keyLen); }
 		RyanJsonGetKey(pJson)[keyLen] = '\0';
 	}
 	else
 	{
 		RyanJsonSetPayloadWhiteKeyByFlag(pJson, RyanJsonFalse);
+		RyanJsonSetPayloadEncodeKeyLenByFlag(pJson, 0);
 	}
 
 	// 设置字符串值
@@ -448,7 +427,7 @@ static RyanJson_t RyanJsonNewNode(RyanJsonNodeInfo_t *info)
 	RyanJsonCheckAssert(NULL != info);
 
 	// 加1是flag的空间
-	uint32_t size = sizeof(struct RyanJsonNode);
+	uint32_t size = sizeof(struct RyanJsonNode) + RyanJsonAlign;
 
 	if (_checkType(info->type, RyanJsonTypeNumber))
 	{
@@ -460,19 +439,7 @@ static RyanJson_t RyanJsonNewNode(RyanJsonNodeInfo_t *info)
 	}
 	else if (_checkType(info->type, RyanJsonTypeArray) || _checkType(info->type, RyanJsonTypeObject)) { size += sizeof(RyanJson_t); }
 
-	if (NULL != info->key || _checkType(info->type, RyanJsonTypeString))
-	{
-		size += sizeof(void *); // 对齐偏移
-		size += sizeof(void *); // key和Str的指针
-	}
-	else if (_checkType(info->type, RyanJsonTypeArray) || _checkType(info->type, RyanJsonTypeObject))
-	{
-		size += sizeof(void *); // 对齐偏移
-	}
-	else
-	{
-		size += sizeof(uint8_t); // 对齐偏移
-	}
+	if (NULL != info->key || _checkType(info->type, RyanJsonTypeString)) { size += sizeof(void *); }
 
 	RyanJson_t pJson = (RyanJson_t)jsonMalloc((size_t)size);
 	if (NULL != pJson)
@@ -497,6 +464,106 @@ static RyanJson_t RyanJsonNewNode(RyanJsonNodeInfo_t *info)
 	return pJson;
 }
 
+/**
+ * @brief 创建一个item对象
+ * 带有key的对象才可以方便的通过replace替换,
+ * !此接口不推荐用户调用
+ *
+ * @param key
+ * @param item
+ * @return RyanJson_t
+ */
+static RyanJson_t RyanJsonCreateItem(const char *key, RyanJson_t item)
+{
+	RyanJsonCheckReturnNull(NULL != item);
+
+	RyanJsonNodeInfo_t nodeInfo = {
+		.type = _checkType(RyanJsonGetType(item), RyanJsonTypeArray) ? RyanJsonTypeArray : RyanJsonTypeObject,
+		.key = key,
+	};
+
+	RyanJson_t newItem = RyanJsonNewNode(&nodeInfo);
+
+	RyanJsonCheckReturnNull(NULL != newItem);
+
+	if (_checkType(RyanJsonGetType(item), RyanJsonTypeArray) || _checkType(RyanJsonGetType(item), RyanJsonTypeObject))
+	{
+		RyanJsonChangeObjectValue(newItem, RyanJsonGetObjectValue(item));
+
+		if (RyanJsonIsKey(item) || RyanJsonIsString(item)) { jsonFree(RyanJsonGetHiddePrt(item)); }
+		jsonFree(item);
+	}
+	else
+	{
+		RyanJsonChangeObjectValue(newItem, item);
+	}
+
+	return newItem;
+}
+
+/**
+ * @brief 提供内存钩子函数
+ *
+ * @param userMalloc
+ * @param userFree
+ * @param userRealloc 可以为NULL
+ * @return RyanJsonBool_e
+ */
+RyanJsonBool_e RyanJsonInitHooks(RyanJsonMalloc_t userMalloc, RyanJsonFree_t userFree, RyanJsonRealloc_t userRealloc)
+{
+	RyanJsonCheckReturnFalse(NULL != userMalloc && NULL != userFree);
+
+	jsonMalloc = userMalloc;
+	jsonFree = userFree;
+	jsonRealloc = userRealloc;
+	return RyanJsonTrue;
+}
+
+char *RyanJsonGetKey(RyanJson_t pJson)
+{
+	RyanJsonCheckReturnNull(NULL != pJson);
+	return (char *)RyanJsonGetHiddenPtrAt(pJson, RyanJsonGetPayloadEncodeKeyLenByFlag(pJson));
+}
+
+char *RyanJsonGetStringValue(RyanJson_t pJson)
+{
+	RyanJsonCheckReturnNull(NULL != pJson);
+
+	uint32_t len = 0;
+	if (RyanJsonIsKey(pJson)) { len = RyanJsonGetPayloadEncodeKeyLenByFlag(pJson) + RyanJsonGetLenKey(pJson) + 1U; }
+
+	return (char *)RyanJsonGetHiddenPtrAt(pJson, len);
+}
+
+int32_t RyanJsonGetIntValue(RyanJson_t pJson)
+{
+	RyanJsonCheckCodeNoReturn(NULL != pJson, { return 0; });
+
+	int32_t intValue;
+	RyanJsonMemcpy(&intValue, RyanJsonGetValue(pJson), sizeof(intValue));
+	return intValue;
+}
+
+double RyanJsonGetDoubleValue(RyanJson_t pJson)
+{
+	RyanJsonCheckCodeNoReturn(NULL != pJson, { return 0; });
+
+	double doubleValue;
+	RyanJsonMemcpy(&doubleValue, RyanJsonGetValue(pJson), sizeof(doubleValue));
+	return doubleValue;
+}
+
+RyanJson_t RyanJsonGetObjectValue(RyanJson_t pJson)
+{
+	RyanJsonCheckCodeNoReturn(NULL != pJson, { return 0; });
+
+	RyanJson_t objValue;
+	RyanJsonMemcpy((void *)&objValue, RyanJsonGetValue(pJson), sizeof(void *));
+	return objValue;
+}
+
+RyanJson_t RyanJsonGetArrayValue(RyanJson_t pJson) { return RyanJsonGetObjectValue(pJson); }
+
 /**
  * @brief 删除json及其子项
  *
@@ -1621,7 +1688,7 @@ RyanJson_t RyanJsonDetachByIndex(RyanJson_t pJson, uint32_t index)
 	if (NULL != prev) { prev->next = nextItem->next; }
 	else
 	{
-		RyanJsonGetObjectValue(pJson) = nextItem->next;
+		RyanJsonChangeObjectValue(pJson, nextItem->next);
 	}
 
 	nextItem->next = NULL;
@@ -1655,7 +1722,7 @@ RyanJson_t RyanJsonDetachByKey(RyanJson_t pJson, const char *key)
 	if (NULL != prev) { prev->next = nextItem->next; }
 	else // 更改的可能是第一个节点
 	{
-		RyanJsonGetObjectValue(pJson) = nextItem->next;
+		RyanJsonChangeObjectValue(pJson, nextItem->next);
 	}
 
 	nextItem->next = NULL;
@@ -1732,7 +1799,7 @@ RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, uint32_t index, RyanJson_t item)
 	if (NULL != prev) { prev->next = item; }
 	else
 	{
-		RyanJsonGetObjectValue(pJson) = item;
+		RyanJsonChangeObjectValue(pJson, item);
 	}
 
 	// nextItem为NULL时这样赋值也是可以的
@@ -1758,28 +1825,6 @@ RyanJsonBool_e RyanJsonAddItemToObject(RyanJson_t pJson, const char *key, RyanJs
 	return RyanJsonInsert(pJson, UINT32_MAX, pItem);
 }
 
-/**
- * @brief 替换json对象节点
- *
- * @param prev
- * @param oldItem
- * @param newItem
- * @return RyanJsonBool_e
- */
-static RyanJsonBool_e RyanJsonReplaceNode(RyanJson_t prev, RyanJson_t oldItem, RyanJson_t newItem)
-{
-	RyanJsonCheckAssert(NULL != oldItem && NULL != newItem);
-
-	// 链接前驱和新节点
-	if (NULL != prev) { prev->next = newItem; }
-
-	// 链接后继和新节点
-	if (NULL != oldItem->next) { newItem->next = oldItem->next; }
-
-	oldItem->next = NULL;
-	return RyanJsonTrue;
-}
-
 /**
  * @brief 通过 索引 替换json对象的子项
  *
@@ -1809,7 +1854,7 @@ RyanJsonBool_e RyanJsonReplaceByIndex(RyanJson_t pJson, uint32_t index, RyanJson
 	}
 
 	RyanJsonReplaceNode(prev, nextItem, item);
-	if (NULL == prev) { RyanJsonGetObjectValue(pJson) = item; }
+	if (NULL == prev) { RyanJsonChangeObjectValue(pJson, item); }
 
 	RyanJsonDelete(nextItem);
 	return RyanJsonTrue;
@@ -1854,7 +1899,7 @@ RyanJsonBool_e RyanJsonReplaceByKey(RyanJson_t pJson, const char *key, RyanJson_
 	}
 
 	RyanJsonReplaceNode(prev, nextItem, item);
-	if (NULL == prev) { RyanJsonGetObjectValue(pJson) = item; }
+	if (NULL == prev) { RyanJsonChangeObjectValue(pJson, item); }
 
 	RyanJsonDelete(nextItem);
 
@@ -1987,43 +2032,6 @@ static RyanJson_t RyanJsonCreateArrayAndKey(const char *key)
 }
 RyanJson_t RyanJsonCreateArray(void) { return RyanJsonCreateArrayAndKey(NULL); }
 
-/**
- * @brief 创建一个item对象
- * 带有key的对象才可以方便的通过replace替换,
- * !此接口不推荐用户调用
- *
- * @param key
- * @param item
- * @return RyanJson_t
- */
-RyanJson_t RyanJsonCreateItem(const char *key, RyanJson_t item)
-{
-	RyanJsonCheckReturnNull(NULL != item);
-
-	RyanJsonNodeInfo_t nodeInfo = {
-		.type = _checkType(RyanJsonGetType(item), RyanJsonTypeArray) ? RyanJsonTypeArray : RyanJsonTypeObject,
-		.key = key,
-	};
-
-	RyanJson_t newItem = RyanJsonNewNode(&nodeInfo);
-
-	RyanJsonCheckReturnNull(NULL != newItem);
-
-	if (_checkType(RyanJsonGetType(item), RyanJsonTypeArray) || _checkType(RyanJsonGetType(item), RyanJsonTypeObject))
-	{
-		RyanJsonGetObjectValue(newItem) = RyanJsonGetObjectValue(item);
-
-		if (RyanJsonIsKey(item) || RyanJsonIsString(item)) { jsonFree(RyanJsonGetHiddePrt(item)); }
-		jsonFree(item);
-	}
-	else
-	{
-		RyanJsonGetObjectValue(newItem) = item;
-	}
-
-	return newItem;
-}
-
 RyanJsonBool_e RyanJsonIsKey(RyanJson_t pJson) { return RyanJsonMakeBool(NULL != pJson && RyanJsonGetPayloadWhiteKeyByFlag(pJson)); }
 RyanJsonBool_e RyanJsonIsNull(RyanJson_t pJson) { return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeNull == RyanJsonGetType(pJson)); }
 RyanJsonBool_e RyanJsonIsBool(RyanJson_t pJson) { return RyanJsonMakeBool(NULL != pJson && RyanJsonTypeBool == RyanJsonGetType(pJson)); }
@@ -2094,7 +2102,7 @@ RyanJson_t RyanJsonDuplicate(RyanJson_t pJson)
 			}
 			else
 			{
-				RyanJsonGetObjectValue(newItem) = item;
+				RyanJsonChangeObjectValue(newItem, item);
 				prev = item;
 			}
 
@@ -2113,12 +2121,6 @@ err:
 	return NULL;
 }
 
-/**
- * @brief 通过删除无效字符、注释等, 减少json文本大小
- *
- * @param text 文本指针
- */
-
 /**
  * @brief 通过删除无效字符、注释等, 减少json文本大小
  *

+ 7 - 5
RyanJson/RyanJson.h

@@ -153,9 +153,11 @@ typedef void *(*RyanJsonRealloc_t)(void *block, size_t size);
 #define RyanJsonGetPayloadWhiteKeyByFlag(pJson)        RyanJsonGetPayloadFlagField((pJson), 4, RyanJsonGetMask(1))
 #define RyanJsonSetPayloadWhiteKeyByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 4, RyanJsonGetMask(1), (value))
 
+// ! 使用超过8字节后一定要注意 RyanJsonSetPayloadFlagField 目前限制uint8_t类型
+// flag空间不够的时候可以把这个字段弃用,用redis的listpack方法将key和keyLen一起表示,内存占用也挺好,但是复杂度高,有空间就保持现在这样
+#define RyanJsonGetPayloadEncodeKeyLenByFlag(pJson)        ((uint8_t)RyanJsonGetPayloadFlagField((pJson), 5, RyanJsonGetMask(2)) + 1)
+#define RyanJsonSetPayloadEncodeKeyLenByFlag(pJson, value) RyanJsonSetPayloadFlagField((pJson), 5, RyanJsonGetMask(2), (value))
 extern RyanJsonBool_e RyanJsonInsert(RyanJson_t pJson, uint32_t index, RyanJson_t item);
-extern void *RyanJsonGetValue(RyanJson_t pJson);
-extern RyanJson_t RyanJsonCreateItem(const char *key, RyanJson_t item); // 需用户释放内存
 /**
  * !!!上面的接口不推荐使用
  *
@@ -245,9 +247,9 @@ extern char *RyanJsonGetKey(RyanJson_t pJson);
 extern char *RyanJsonGetStringValue(RyanJson_t pJson);
 extern int32_t RyanJsonGetIntValue(RyanJson_t pJson);
 extern double RyanJsonGetDoubleValue(RyanJson_t pJson);
-#define RyanJsonGetBoolValue(pJson)   RyanJsonGetPayloadBoolValueByFlag(pJson)
-#define RyanJsonGetArrayValue(pJson)  (*(RyanJson_t *)RyanJsonGetValue(pJson))
-#define RyanJsonGetObjectValue(pJson) (*(RyanJson_t *)RyanJsonGetValue(pJson))
+extern RyanJson_t RyanJsonGetObjectValue(RyanJson_t pJson);
+extern RyanJson_t RyanJsonGetArrayValue(RyanJson_t pJson);
+#define RyanJsonGetBoolValue(pJson) RyanJsonGetPayloadBoolValueByFlag(pJson)
 
 /**
  * @brief 添加相关函数

+ 14 - 0
RyanJson/RyanJsonConfig.h

@@ -36,6 +36,14 @@ extern "C" {
 // 是否启用assert
 // #define RyanJsonEnableAssert
 
+// 是否支持未对齐访问,未定义时会根据平台选择,
+// 一般不用管,如果你明白你的需求就自己定义
+// true 表示支持未对齐访问
+// false 表示不支持未对齐访问
+#ifndef RyanJsonUnalignedAccessSupported
+#define RyanJsonUnalignedAccessSupported true
+#endif
+
 // 限制解析数组/对象中嵌套的深度
 // RyanJson使用递归 序列化/反序列化 json
 // 请根据单片机资源合理设置以防止堆栈溢出。
@@ -61,6 +69,12 @@ extern "C" {
 #define RyanJsonAssert(EX) (void)(EX)
 #endif
 
+#if true != RyanJsonUnalignedAccessSupported
+#define RyanJsonAlign sizeof(void *)
+#else
+#define RyanJsonAlign sizeof(uint8_t)
+#endif
+
 #ifdef __cplusplus
 }
 #endif

+ 4 - 7
RyanJson/RyanJsonUtils.h

@@ -24,15 +24,12 @@ extern RyanJson_t RyanJsonGetObjectByIndexs(RyanJson_t pJson, uint32_t index, ..
 extern RyanJson_t RyanJsonGetObjectByKeys(RyanJson_t pJson, const char *key, ...);
 
 /**
- * @brief 可使用此宏进行嵌套式查找,例如 RyanJsonGetObjectToKey(json, "test", "inter")
- * 
+ * @brief 可使用此宏进行嵌套式查找,
+ * 例如 RyanJsonGetObjectToKey(json, "test", "inter")
+ * 例如 RyanJsonGetObjectToIndex(json, 0, 2)
+ *
  */
 #define RyanJsonGetObjectToKey(pJson, key, ...)     RyanJsonGetObjectByKeys(pJson, (key), ##__VA_ARGS__, NULL)
-
-/**
- * @brief 可使用此宏进行嵌套式查找,例如 RyanJsonGetObjectToIndex(json, 0, 2)
- * 
- */
 #define RyanJsonGetObjectToIndex(pJson, index, ...) RyanJsonGetObjectByIndexs(pJson, (index), ##__VA_ARGS__, UINT32_MAX)
 
 #define RyanJsonHasObjectToKey(pJson, key, ...)     RyanJsonMakeBool(RyanJsonGetObjectByKeys(pJson, key, ##__VA_ARGS__, NULL))

+ 1 - 1
test/RyanJsonMemoryFootprintTest.c

@@ -129,7 +129,7 @@ RyanJsonBool_e RyanJsonMemoryFootprintTest(void)
 		  "}}";
 	printfJsonCompera(jsonstr);
 
-	printf("\r\n--------------------------- 对象占多json数据测试 --------------------------\r\n");
+	printf("\r\n--------------------------- 全是对象json数据测试 --------------------------\r\n");
 	jsonstr =
 		"{\"message\":\"success感谢又拍云(upyun.com)提供CDN赞助\",\"status\":200,\"date\":\"20230822\",\"time\":\"2023-08-22 "
 		"09:44:54\",\"cityInfo\":{\"city\":\"郑州市\",\"citykey\":\"101180101\",\"parent\":\"河南\",\"updateTime\":\"07:46\"},"

+ 7 - 2
test/fuzzer/RyanJsonFuzzer.c

@@ -45,7 +45,7 @@ static RyanJsonBool_e RyanJsonFuzzerTestByParseAndPrint(RyanJson_t pJson, const
 		return RyanJsonFalse;
 	});
 
-    // 测试多次打印结果是否一致
+	// 测试多次打印结果是否一致
 	{
 		uint32_t len3 = 0;
 		char *jsonStr3 = RyanJsonPrint(jsonRoot, 100, size % 2 ? RyanJsonFalse : RyanJsonTrue, &len3); // 以带格式方式将数据打印出来
@@ -243,9 +243,11 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachGet2(RyanJson_t lastJson, RyanJ
 {
 	RyanJsonIsNull(pJson);
 
-	RyanJsonAssert(NULL == RyanJsonGetValue(NULL));
 	RyanJsonAssert(NULL == RyanJsonGetKey(NULL));
 	RyanJsonAssert(NULL == RyanJsonGetStringValue(NULL));
+	RyanJsonAssert(0 == RyanJsonGetIntValue(NULL));
+	RyanJsonAssert(0 == RyanJsonGetDoubleValue(NULL));
+	RyanJsonAssert(NULL == RyanJsonGetObjectValue(NULL));
 
 	RyanJsonAssert(NULL == RyanJsonGetObjectByKey(NULL, NULL));
 	RyanJsonAssert(NULL == RyanJsonGetObjectByKey(pJson, NULL));
@@ -346,6 +348,9 @@ static RyanJsonBool_e RyanJsonFuzzerTestByForEachCreate(RyanJson_t pJson, uint32
 		RyanJsonAssert(RyanJsonFalse == RyanJsonChangeKey(pJson, "NULL"));
 	}
 
+	RyanJsonAssert(RyanJsonFalse == RyanJsonChangeIntValue(NULL, 0));
+	RyanJsonAssert(RyanJsonFalse == RyanJsonChangeDoubleValue(NULL, 0));
+
 	RyanJsonAssert(RyanJsonFalse == RyanJsonAddItemToObject(NULL, NULL, NULL));
 	RyanJsonAssert(RyanJsonFalse == RyanJsonAddItemToObject(pJson, NULL, NULL));
 

+ 70 - 71
xmake.lua

@@ -1,68 +1,68 @@
+-- 自动生成 compile_commands.json,方便 VSCode/Clangd 做代码补全与跳转
 add_rules("plugin.compile_commands.autoupdate", {outputdir = ".vscode"})
-target("RyanJson",function()
-    set_kind("binary")
 
-    -- set_toolchains("gcc")  -- 确保使用 GCC
-    set_toolchains("clang")
-    set_plat("linux")
-    set_arch("x86")
-    set_languages("gnu99") -- 关键!启用 GNU 扩展
-    add_defines("isEnableFuzzer")
-    add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
-    add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true} )
+target("RyanJson", function()
+    -- 目标类型:二进制可执行文件
+    set_kind("binary")
 
-    set_policy("build.ccache", false)
-    -- set_optimize("smallest") -- -Os
-    -- set_optimize("faster") -- -O2
-    set_optimize("fastest") -- -O3
-    -- set_optimize("aggressive") -- -Ofast
+    -- 编译工具链与平台配置
+    -- set_toolchains("gcc")  -- 使用 GCC
+    set_toolchains("clang")   -- 使用 Clang 编译器
+    set_plat("linux")         -- 平台:Linux
+    set_arch("x86")           -- 架构:x86(32位)
+    set_languages("gnu99")    -- 使用 GNU C99 标准,启用 GNU 扩展
 
-    -- 启用全部警告
-    set_warnings("everything") -- -Wall -Wextra -Weffc++ / -Weverything
+    -- 定义宏:启用 Fuzzer 功能
+    -- Fuzzer 与覆盖率相关编译/链接选项
+    add_defines("isEnableFuzzer")
+    add_cxflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true})
+    add_ldflags("-fsanitize=fuzzer", "-fprofile-instr-generate", "-fcoverage-mapping", {force = true})
 
-    -- 链接器选项:生成 map 文件
-    -- add_ldflags("-Wl,-Map=$(buildir)/RyanJson.map")
+    -- 编译优化策略
+    set_policy("build.ccache", false) -- 禁用 ccache 缓存
+    set_optimize("fastest")           -- 使用 -O3,最高级别优化
 
-    -- 开启库加固(需与 -O2 以上配合
-    -- add_defines("_FORTIFY_SOURCE=2")   -- glibc 格式/内存函数加固
+    -- 警告设置:启用所有警告(Clang 下相当于 -Weverything
+    set_warnings("everything")
 
-    -- 链接器安全硬化与优化
+    -- 链接器安全硬化与优化选项
     add_ldflags(
-        "-flto",                    -- 链接时优化(启用 LTO,便于 CFI 等
+        "-flto",                    -- 启用 LTO(链接时优化
         "-fPIE",                    -- 位置无关可执行
         "-pie",                     -- 与 -fPIE 搭配,启用 ASLR
-        "-fno-omit-frame-pointer",  -- 保留帧指针,便于崩溃分析
-        "-fstack-clash-protection", -- 栈碰撞保护(平台支持时有效)
-        "-Wl,-z,relro",             -- 只读重定位(硬化)
-        "-Wl,-z,now",               -- 立即绑定(与 relro 搭配)
+        "-fno-omit-frame-pointer",  -- 保留帧指针,便于调试和崩溃分析
+        "-fstack-clash-protection", -- 栈碰撞保护
+        "-Wl,-z,relro",             -- 重定位表只读
+        "-Wl,-z,now",               -- 立即绑定符号
         "-Wl,-z,noexecstack",       -- 栈不可执行
-        "-Wl,-z,separate-code",     -- 代码与数据段分离
+        "-Wl,-z,separate-code",     -- 代码与数据段分离
         {force = true}
     )
 
-    -- Sanitizer 检测项(运行时错误)
+    -- Sanitizer 检测项:运行时错误检测
+    add_cxflags("-fsanitize=alignment", "-fno-sanitize-recover=undefined", {force = true})
     add_ldflags(
-        "-fsanitize=address", -- 内存越界、释放后使用
-        "-fsanitize=leak", -- 内存泄漏
-        "-fsanitize=undefined", -- 未定义行为(除零、溢出、无效移位等)
-        "-fsanitize=pointer-compare", -- 无效指针比较
-        "-fsanitize=pointer-subtract", -- 无效指针相减
-        "-fsanitize=bounds", -- 数组越界
-        "-fsanitize=float-divide-by-zero", -- 浮点除零
-        "-fsanitize=float-cast-overflow", -- 浮点转整数溢出
+        "-fsanitize=alignment",             -- 检查未对齐访问
+        "-fno-sanitize-recover=undefined",  -- 遇到未定义行为立即终止
+        "-fsanitize=address",               -- 内存越界、释放后使用
+        "-fsanitize=leak",                  -- 内存泄漏
+        "-fsanitize=undefined",             -- 常见未定义行为
+        "-fsanitize=pointer-compare",       -- 无效指针比较
+        "-fsanitize=pointer-subtract",      -- 无效指针相减
+        "-fsanitize=bounds",                -- 数组越界
+        "-fsanitize=float-divide-by-zero",  -- 浮点除零
+        "-fsanitize=float-cast-overflow",   -- 浮点转整数溢出
         -- "-fsanitize=thread",      -- 多线程数据竞争
         -- "-fsanitize=memory",      -- 未初始化内存使用
         -- "-fsanitize=safe-stack",  -- 栈分离机制
         -- "-fsanitize=cfi",         -- 控制流完整性(需 LTO 与 Clang)
-        -- "-fsanitize=alignment", -- 检测未对齐的内存访问
-        -- "-fno-sanitize=alignment", -- 某些平台不兼容
         {force = true}
     )
 
-    -- 编译器警告与静态分析(开发期错误检测,Clang 兼容)
+    -- 编译器警告与静态分析
     add_cxflags(
-        "-g3",                     -- 生成调试信息"
-        "-pedantic",               -- 强制遵循 ISO C 标准
+        "-g3",                     -- 生成详细的调试信息
+        "-pedantic",               -- 严格遵循 ISO C 标准
         "-Wall",                   -- 常见警告
         "-Wextra",                 -- 额外警告
         "-Wconversion",            -- 隐式类型转换风险
@@ -72,12 +72,12 @@ target("RyanJson",function()
         "-Wold-style-definition",  -- 检测旧式函数定义
         "-Wimplicit-fallthrough",  -- switch/case 未显式 fallthrough
         "-Wshadow",                -- 局部变量遮蔽
-        "-Wcast-align",            -- 类型转换对齐问题
+        "-Wcast-align",            -- 类型转换可能导致未对齐
         "-Wpointer-arith",         -- 指针运算风险
         "-Warray-bounds",          -- 数组越界访问
-        "-Wshift-overflow",        -- 位移造成的溢出
-        "-Wformat-truncation",     -- 格式化字符串截断风险(替代 stringop-truncation)
-        "-Walloc-size",            -- 分配大小问题(替代 alloc-zero)
+        "-Wshift-overflow",        -- 位移溢出
+        "-Wformat-truncation",     -- 格式化字符串截断风险
+        "-Walloc-size",            -- 分配大小问题
         "-Wnull-dereference",      -- 空指针解引用
         "-Wtautological-compare",  -- 恒真/恒假的比较
         "-Wstrict-overflow",       -- 有符号溢出优化假设
@@ -86,49 +86,48 @@ target("RyanJson",function()
         "-Wredundant-decls",       -- 重复声明
         "-Wunreachable-code",      -- 不可达代码
         "-Wtype-limits",           -- 比较恒真/恒假的表达式(如 unsigned < 0)
-        "-Wshift-negative-value",  -- 对负数进行移位
+        "-Wshift-negative-value",  -- 对负数移位
         "-Wdiv-by-zero",           -- 除以零(编译期可分析)
         "-Wformat-security",       -- 格式化字符串安全问题
         "-Wdisabled-optimization", -- 被禁用的优化
         "-Wreturn-local-addr",     -- 返回局部变量地址
-        "-Wdeprecated",            -- 使用已弃用特性
-        -- "-Wunsafe-buffer-usage",   -- 不安全的数组/指针用法(Clang 新增)
+        "-Wdeprecated",            -- 使用已弃用特性
+        "-Wunsafe-buffer-usage",   -- 不安全的数组/指针用法
         "-Wuninitialized",         -- 使用未初始化变量
         "-fstack-protector-strong",-- 栈保护
-        -- 进一步增强(可选,按需开启)
-        "-Wmissing-include-dirs",      -- 头文件目录缺失
-        "-Wcast-qual",                 -- 丢弃 const/volatile 限定符的转换
+        "-Wmissing-include-dirs",  -- 头文件目录缺失
+        "-Wcast-qual",             -- 丢弃 const/volatile 限定符
         "-Wconditional-uninitialized", -- 条件路径未初始化
         "-Wcovered-switch-default",    -- default 覆盖所有枚举值
-        "-Wformat-nonliteral",         -- 非字面量格式串
-        "-Wformat-signedness",         -- 格式化与符号性不匹配
-        "-Wvla",                       -- 可变长度数组(不安全/不建议使用)
-        "-fno-common",                 -- 禁止旧式多重定义(链接期更严格)
+        "-Wformat-nonliteral",     -- 非字面量格式串
+        "-Wformat-signedness",     -- 格式化与符号性不匹配
+        "-Wvla",                   -- 可变长度数组
+        "-fno-common",             -- 禁止旧式多重定义
         "-fno-strict-aliasing",        -- 禁止严格别名优化,减少别名相关 UB 风险
-        "-Wno-documentation", -- 临时变比
-        "-Wno-parentheses-equality",
+        "-Wdocumentation",
+        "-Wparentheses-equality",
+        "-Wno-documentation",      -- 临时关闭文档警告
+        -- "-Wno-parentheses-equality", -- 临时关闭括号比较警告
         {force = true}
     )
 
-    add_includedirs('./test/fuzzer', {public = true})
-    add_files('./test/fuzzer/*.c', {public = true})
-
-    --加入代码和头文件
+    -- 公共头文件目录
     add_includedirs('./RyanJson', {public = true})
-    add_files('./RyanJson/*.c', {public = true})
-
     add_includedirs('./example', {public = true})
+    add_includedirs('./test/fuzzer', {public = true})
     add_includedirs('./test', {public = true})
     add_includedirs('./test/valloc', {public = true})
     add_includedirs('./test/baseTest', {public = true})
     add_includedirs('./externalModule/cJSON', {public = true})
     add_includedirs('./externalModule/yyjson', {public = true})
 
+    -- 源文件分开列出,保持清晰结构
+    add_files('./RyanJson/*.c', {public = true})
     add_files('./example/*.c', {public = true})
-    add_files('./test/*.c', {public = true}, {cxflags = "-w"})
-    add_files('./test/valloc/*.c', {public = true}, {cxflags = "-w"})
-    add_files('./test/baseTest/*.c', {public = true}, {cxflags = "-w"})
-    add_files('./externalModule/cJSON/*.c', {public = true}, {cxflags = "-w"})
-    add_files('./externalModule/yyjson/*.c', {public = true}, {cxflags = "-w"})
-
-end)
+    add_files('./test/fuzzer/*.c', {public = true})
+    add_files('./test/*.c', {public = true}, {cxflags = "-w"})          -- 测试代码,关闭警告
+    add_files('./test/valloc/*.c', {public = true}, {cxflags = "-w"})   -- valloc 测试,关闭警告
+    add_files('./test/baseTest/*.c', {public = true}, {cxflags = "-w"}) -- 基础测试,关闭警告
+    add_files('./externalModule/cJSON/*.c', {public = true}, {cxflags = "-w"}) -- 第三方库 cJSON,关闭警告
+    add_files('./externalModule/yyjson/*.c', {public = true}, {cxflags = "-w"}) -- 第三方库 yyjson,关闭警告
+end)