背景

这几天在使用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. shell脚本实现查找文件夹下重复的文件,并提供删除功能

    Windows下有软件FindDupFile,可以搜索指定目录及其下子目录,列出所有内容完全相同的文件(文件名可能不同),然后由用户选择删除重复的文件. 然而shell脚本却可以使用几行的命令完成与此 ...

  2. PHPexcel:多sheet上传和下载

    excel表格上传和下载,断断续续写了很久,赶紧记下来万一以后忘记就亏大了= = 数据库有三张表:

  3. PHP 计算页面执行时间

    PHP 计算页面执行时间 < ?php class runtime { var $StartTime = 0; var $StopTime = 0; function get_microtime ...

  4. php 输出昨天,今天,明天是星期几的方法

    <?php //php判断某一天是星期几的方法 function getWeek($unixTime=''){ $unixTime=is_numeric($unixTime)?$unixTime ...

  5. ASP.NET MVC 4.0的Action Filter

    有时候你想在调用action方法之前或者action方法之后处理一些逻辑,为了支持这个,ASP.NET MVC允许你自定义创建action过滤器.Action过滤器是自定义的Attributes,用来 ...

  6. python 微信推送模板消息

    #!/usr/bin/env python #-*- coding: utf-8 -*- import httplib import json import MySQLdb #从数据库中获取acces ...

  7. Ubuntu12.04下载Android4.0.1源码全过程,附若干问题解决[转]

    学校里一直在做应用层开发,考虑到日后就业问题,这次决定研究源码和驱动,并进行编译.没想到就下载源码这一步折腾了我整整两天,期间遇到很多问题,哎,记录于此,希望日后再下源码的人不要再走无谓的弯路了.事实 ...

  8. PHP安装OPENSSL扩展模块

    新项目上线时,PHP开发同事反映邮件功能不能正常使用. 原来是用465的SMTP加密端口,不是25端口.那要为当前的PHP安装OPENSSL扩展啦. 还好,网上有很多,弄一个过来就搞定. http:/ ...

  9. MYSQL错误解决:ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)

    ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' ( ...

  10. wpf只运行一个实例

    原文:wpf只运行一个实例 在winform下,只运行一个实例只需这样就可以: 1. 首先要添加如下的namespace: using System.Threading; 2. 修改系统Main函数, ...