#pragma in gcc

When the ANSI C standard was under development, thepragma directive was introduced. Borrowed from Ada, #pragmais used to convey hints to the compiler, such as the desireto expand a particular function as in-line or suppress somerange checks. #pragma met with some initial resistancee froma gcc implementor, who took the "implementation-defined" effectvery literally. In gcc version 1.34, the use of pragma causedthe compiler to stop compiling and launch a computer game instead.The gcc version 1.34 manual said:

"The #pragma command is specified in the ANSI standard to havean arbitrary implementation-defined effect. In GNU C preprocessor,#pragma first attempts to run the game "rogue"; if that fails,it tries to run the game "hack"; if that fails, it tries to runGNU Emacs displaying Tower Of Hanoi; if that fails, it reportsa fatal error. In any case, preprocessing does not continue."

Here's an excerpt from the gcc source, version 1.35,released in 1989 (note the "#if 0"):

#if 0
/* This was a fun hack, but #pragma seems to start to be useful.
   By failing to recognize it, we pass it through unchanged to cc1. */

/*
 * the behavior of the #pragma directive is implementation defined.
 * this implementation defines it as follows.
 */
do_pragma ()
{
    close (0);
    if (open ("/dev/tty", O_RDONLY, 0666) != 0)
        goto nope;
    close (1);
    if (open ("/dev/tty", O_WRONLY, 0666) != 1)
        goto nope;
    execl ("/usr/games/hack", "#pragma", 0);
    execl ("/usr/games/rogue", "#pragma", 0);
    execl ("/usr/new/emacs", "-f", "hanoi", "9", "-kill", 0);
    execl ("/usr/local/emacs", "-f", "hanoi", "9", "-kill", 0);
nope:
    fatal ("You are in a maze of twisty compiler features, all different");
}
#endif


/* Copyright (c) 2009-2017 Dave Gamble and cJSON contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /* cJSON */ /* JSON parser in C. */ /* disable warnings about old C89 functions in MSVC */ #if !defined(_CRT_SECURE_NO_DEPRECATE) && defined(_MSC_VER) #define _CRT_SECURE_NO_DEPRECATE #endif #ifdef __GNUC__ #pragma GCC visibility push(default) #endif #if defined(_MSC_VER) #pragma warning (push) /* disable warning about single line comments in system headers */ #pragma warning (disable : 4001) #endif #include <string.h> #include <stdio.h> #include <math.h> #include <stdlib.h> #include <float.h> #include <limits.h> #include <ctype.h> #ifdef ENABLE_LOCALES #include <locale.h> #endif #if defined(_MSC_VER) #pragma warning (pop) #endif #ifdef __GNUC__ #pragma GCC visibility pop #endif #include "JSON.h" /* define our own boolean type */ #define true ((cJSON_bool)1) #define false ((cJSON_bool)0) typedef struct { const unsigned char *json; size_t position; }
最新发布
04-03
<think>好的,我现在需要详细分析cJSON的源码实现细节。首先,用户想了解cJSON这个C语言的JSON解析库的具体实现,所以我得回忆一下cJSON的结构和解析流程。 首先,cJSON是一个轻量级的库,主要用结构体来表示JSON数据。核心结构体应该是cJSON,里面包含类型、键、值、兄弟节点和子节点等信息。比如,类型可能有对象、数组、字符串、数字等,这些在源码里应该用枚举来定义。 然后,解析过程应该是将输入的JSON字符串转换为cJSON结构体的树形结构。解析函数大概会从字符串起始位置开始,逐个字符分析,跳过空白字符,然后根据遇到的字符(如{、[、"、数字等)来决定创建对应的节点。例如,遇到{就表示开始解析一个对象,里面会有多个键值对,每个键值对可能作为子节点链接起来。 字符串解析部分需要注意转义字符的处理,比如\"、\n、\uXXXX等。这部分可能需要一个专门的函数来解析字符串,并处理转义,同时分配内存存储解析后的字符串。 数字解析方面,cJSON可能使用strtod之类的库函数将字符串转换为double或int,但需要考虑不同平台和编译器的兼容性,特别是非数字(NaN)和无穷大(Infinity)的情况,不过JSON标准可能不支持这些,所以需要处理错误。 内存管理方面,cJSON应该在解析时动态分配内存,用户需要负责释放。因此,每个cJSON结构体及其相关数据(如字符串、数组元素)都需要正确的内存分配和释放,避免内存泄漏。例如,cJSON_Delete函数会递归释放节点及其子节点。 生成JSON字符串的部分,即将cJSON结构体转换回字符串,可能需要递归遍历节点,根据类型生成对应的字符串表示,处理缩进和格式,对于字符串需要处理转义字符的反向转换。 错误处理机制方面,解析过程中遇到语法错误时,cJSON需要能够报告错误位置和类型。可能通过全局变量或返回值来传递错误信息,比如返回NULL并设置错误指针的位置。 用户提供的引用中提到了jsmn,另一个C语言JSON解析库,但用户的问题是关于cJSON的,所以需要专注于cJSON本身的实现,不过可能可以对比两者在解析策略上的差异,比如cJSON是构建完整的树结构,而jsmn可能是基于令牌的。 需要确认源码中的关键函数,比如cJSON_Parse、parse_object、parse_array、parse_string、parse_number等。每个函数的具体实现步骤,比如parse_object会循环解析键值对,直到遇到},每个键值对创建为一个cJSON节点,并链接到父节点的child或兄弟节点的next指针。 另外,需要注意cJSON的线程安全性,可能在解析时使用全局状态,但如果是可重入的实现,可能每个解析上下文都有独立的状态,但需要查阅源码确认。 最后,总结实现细节时要结构清晰,分点说明核心结构体、解析流程、内存管理、错误处理等部分,确保用户能理解cJSON的内部工作机制。</think>### cJSON源码实现细节分析 #### 1. 核心数据结构 cJSON使用结构体`cJSON`表示所有JSON数据类型,包含以下核心字段: ```c typedef struct cJSON { struct cJSON *next, *prev; // 兄弟节点指针 struct cJSON *child; // 子节点指针(用于对象/数组) int type; // 数据类型(如cJSON_Object、cJSON_String) char *valuestring; // 字符串类型值 double valuedouble; // 数值类型值 char *string; // 键名(对象成员的名称) } cJSON; ``` 数据类型通过`type`字段标识,使用枚举定义如`cJSON_True`、`cJSON_Number`等[^1]。 #### 2. 解析流程 解析入口为`cJSON_Parse()`函数,主要步骤包括: - **词法分析**:跳过空白字符,识别JSON结构标记(如`{`、`[`) - **递归下降解析**: - `parse_object()`处理对象类型,循环解析键值对 - `parse_array()`处理数组类型,逐个解析元素 - `parse_value()`根据首字符分发到具体类型解析 - **字符串处理**:`parse_string()`处理转义字符和Unicode编码 - **数值解析**:`parse_number()`调用`strtod`转换数字 示例代码片段: ```c static const char *parse_object(cJSON *item, const char *value) { if (*value != '{') return 0; // 验证起始字符 item->type = cJSON_Object; value = skip(value+1); while (*value != '}') { cJSON *child = cJSON_New_Item(); // 创建新节点 value = parse_string(child, value); // 解析键 value = skip(value); if (*value != ':') return 0; // 验证分隔符 value = skip(parse_value(child, skip(value+1))); // 解析值 item->child = child; // 挂载子节点 value = skip(value); } return value+1; } ``` #### 3. 内存管理 - **动态分配**:使用`cJSON_malloc`/`cJSON_free`管理内存(可自定义分配器) - **树形结构释放**:`cJSON_Delete()`通过递归遍历释放所有子节点 ```c void cJSON_Delete(cJSON *c) { while (c) { cJSON *next = c->next; if (c->child) cJSON_Delete(c->child); cJSON_free(c->string); cJSON_free(c->valuestring); cJSON_free(c); c = next; } } ``` #### 4. 特殊处理机制 - **字符串转义**:处理`\"`、`\n`等转义字符时创建临时缓冲区 - **数值精度**:直接使用`double`存储数值,可能丢失精度但保持轻量 - **错误定位**:通过全局变量`cJSON_GetErrorPtr()`返回错误位置指针 #### 5. 生成优化 `cJSON_Print()`通过预计算缓冲区大小减少内存重分配: ```c static char* print_value(const cJSON *item, int depth, int fmt) { switch (item->type) { case cJSON_String: return print_string(item->valuestring); case cJSON_Number: return print_number(item); // 其他类型处理... } } ``` ### 关键实现特点 1. **单文件实现**:所有功能集中在`cJSON.c`和`cJSON.h`中 2. **无递归限制**:通过迭代代替深层递归防止栈溢出 3. **严格标准**:完全遵循RFC 8259 JSON规范
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值