背景

这几天在使用cocos2d-x读取磁盘文件的时候,发现了CCFileUtils中一点不合理的地方,特此记录,以供研讨。

项目结构

①我使用的是cocos2d-x 2.1.3版本,CCFileUtils::getFileData的函数签名为:

但据观测,即使是最新版的cocos2d-x 3.2,这部分声明和实现仍没有变化。

②我们假设在项目Resources目录下,有data.txt,其中内容大致为下图:

③下面以win32和android两种平台做对比来分析其中出现的问题。

Win32

①读取文件的代码

②实际执行的读取代码

文件路径:cocos2dx\platform\CCFileUtils.cpp

③过程分析

在Windows中,行结尾符是”\r\n”,所以当程序执行完381行时,

*pSize = ( 5+2+6+2+6 , 21 );

当程序执行完384行时,

*pSize = ( 5+1+6+1+6 , 19 );

当程序返回时,

*pSize == 19; //没有问题

sizeof(pBuffer) == 21; //没有问题

pBuffer == “apple\norange\nbananba?????”; //问题很严重

④结果

当执行步骤①的代码时,我们使得data指向了这样一个字符串:

1.一段以”r”模式读取文件的代码,却在其中包含了’\n’;

2.这个字符串没有’\0’结尾。

这里的问题很好解决,只要我们添加下面一条语句,就可以避免悲剧:

data[pSize] = ‘\0’;

Windows平台上的问题很好解决,下面我们转向android.

Android

①读取文件的代码

②实际执行的读取代码

文件路径:cocos2dx\platform\android\CCFileUtilsAndroid.cpp

③过程分析

由于Android平台上行结尾符为\r,所以当执行完415行时,

*pSize = ( 5+1+6+1+6 , 19 );

sizeof(pBuffer) == 19

有问题吗?很严重。

④结果

下面回到步骤①,此时的data指向了一个字符串,这个字符串:

1.一段以”r”模式读取文件的代码,却在其中包含了’\n’;

2.这个字符串没有’\0’结尾。

但是,此时我们不能使用win32平台的解决方案。

data[size] = ‘\0’; //数组越界!

data[size-1] = ‘\0’;//banana中的最后一个a会被删除

此时,在语言层面上,只有把这段内存复制到一个更安全的地方,才可以解决这种冲突。如果你直接操纵data,几乎可以肯定会出问题。

错误解法:string str = (char*)data;

正确解法:string str( data, data+size );

结论

CCFileUtils::getFileData,一旦你以”r”模式来使用它,data就会变成一个没有’\0’结尾的字符串;一旦你在一个行结尾符是由单个字节组成的系统中使用它,你就不能给它加一个’\0’。如果不注意这两点,几乎可以肯定会误用这个函数。所以使用它的时候,请谨慎!

并且,请使用string str( data, data+size );的形式来复制这个易错字符串。

PS

话说这个函数的声明和实现相当容易被误用,不仔细分析几乎一定会被误用,因为其中的一些做法完全是和常识相违背的,不知道cocos2d-x的团队为什么不修改一下。

CCFileUtils::getFileData疑惑的更多相关文章

  1. cocos2d::CCFileUtils::sharedFileUtils()->getFileData(szFile, "r", &bufferSize) 不同平台返回值不一样

    string pathKey = CCFileUtils::sharedFileUtils()->fullPathForFilename(fileName); unsigned char* pB ...

  2. 基于Quick-cocos2d-x的资源更新方案 二

    写在前面 又是12点半了,对于一个程序员来说,这是一个黄金时间,精力旺盛,我想,是最适合整理和分享一些思路的时候了. 自从上次写了 基于Quick-cocos2d-x的资源更新方案 同样可见quick ...

  3. cocos2dx游戏资源加密之XXTEA

    在手机游戏当中,游戏的资源加密保护是一件很重要的事情. 我花了两天的时间整理了自己在游戏当中的资源加密问题,实现了跨平台的资源流加密,这个都是巨人的肩膀之上的. 大概的思路是这样的,游戏资源通过XXT ...

  4. cocos2dx 不同平台上加载文件

    原文转自:http://blog.sina.com.cn/s/blog_62b2318d0101eozt.html cocos2dx在不同平台上读取资源文件时的处理方式是不同的. 在ios下,程序调用 ...

  5. 如何学习 cocos2d-x ?

    发表于 04/23/2014 作者 zrong — 24 条评论 ↓ 11,687 次查看 本站文章除注明转载外,均为本站原创或者翻译. 本站文章欢迎各种形式的转载,但请18岁以上的转载者注明文章出处 ...

  6. cocos2d-x lua 中使用protobuf并对http进行处理

    cocos2d-x lua 中使用protobuf并对http进行处理 本文介绍 cocos2d-x lua 中使用http 和 基于cocos2d-x 对lua http的封装(部分ok) 本博客链 ...

  7. Atitit 图像处理的心得与疑惑 attilax总结

    Atitit 图像处理的心得与疑惑 attilax总结 1.1. 使用类库好不好??还是自己实现算法1 1.2. 但是,如果遇到类库体积太大,后者没有合适的算法,那就只能自己开发算法了1 1.3. 如 ...

  8. 每日一记-mybatis碰到的疑惑:String类型可以传入多个参数吗

    碰到一个觉得很疑惑的问题,Mybatis的parameterType为String类型的时候,能够接收多个参数的吗? 背景 初学Mybatis的时候,看的教程和书籍上都是在说基本的数据类型如:int. ...

  9. 解决上一篇jquery中on的疑惑

    内容都是来自:http://www.365mini.com/page/jquery-on.htm.这里做一下收藏.文章的最后  疑问和解答可以解决所有的疑惑  看了之后能更好的整篇文章. on()函数 ...

随机推荐

  1. POj3421 X-factor Chains(质因数分解+排列组合)

    POj3421X-factor Chains 一开始没读懂题意,不太明白 Xi | Xi+1 where a | b means a perfectly divides into b的意思,后来才发现 ...

  2. Mysql 索引的基础(上)

    要理解Mysql 中索引是如何工作的,最简单的方法是去看一看书的"索引部分":如果想在一本书中找到某个特定的主题,一般先看书的"索引",找到对应的页码. 在My ...

  3. CentOS7.1 使用资源搜集

    1.配置java环境 -openjdk* 测试 java -version 2.安装Tomcat8.0.35 点击题目可以参考源网页,但有些代码无法执行,更改如下(亲测可行): 一定要先安装java环 ...

  4. php测试题整理(0519)

    1.B/S架构和C/S架构: B/S架构是依托于浏览器的网络系统,C/S架构是基于客户端的. B/S架构: 随着Internet和WWW的流行,以往的主机/终端和C/S都无法满足当前的全球网络开放.互 ...

  5. centos6.7下 编译安装MySQL5.7

    centos6.7下编译安装MySQL5.7 准备工作 #-----依赖包及MySQL和boost安装包----- #yum包安装: shell> yum -y install gcc-c++ ...

  6. 智能的PHP缩图类

    *作者:落梦天蝎(beluckly)*完成时间:2006-12-18*类名:CreatMiniature*功能:生成多种类型的缩略图*基本参数:$srcFile,$echoType*方法用到的参数:$ ...

  7. 万维网发布服务(w3svc)已停止,除非万维网发布服务(w3svc)正在运行。

    近来遇到一个IIS服务启动问题,重启服务器PC后,网站启动的时候,提示“ 万维网发布服务(w3svc)已停止,除非万维网发布服务(w3svc)正在运行”. 解决方法: 点击"开始" ...

  8. S3C2440的GPIO

    S3C2440一共有A B C D E F G H J 共九组IO口,一共是130个,每组IO口的个数如下图所示, 其中A组IO口只有输出功能,没有输入功能, 关于GPXCON寄存器,这个寄存器用来配 ...

  9. 用js 做大图轮播方法(一)

    //html部分 <div id="wrap"> <div id="slider"> <a target="_blank ...

  10. C++类的数组元素查找最大值问题

    找出一个整型数组中的元素的最大值. /*找出一个整型数组中的元素的最大值.*/ #include <iostream> using namespace std; class ArrayMa ...