含蓄的作业本
3 月前 |
开发过程中,未意识到文件可能大于int的最大值,所以埋下了隐患。今天被测试提了个bug。主要原因是
QJsonValue
的
toInt()
返回的是4字节的
int
类型,拿来存一个大于有符号四字节整数的值会溢出。这种边界值界定不明确导致bug的情况还是比较常见,做个总结分享帮助大家避坑。
此外就是csdn上对于这块的教程属实是又少又粗略。
* 本程序是测试Qt 程序存储64位整数 至Json文件 并加载读出 # include <QtCore/QCoreApplication> # include <QJsonObject> # include <QJsonValue> # include <QDebug> # include <QDir> # include <QJsonDocument> # include <QByteArray> # include <iostream> # include <climits> # include <cfloat> # include <iomanip> void printTypeInfo ( ) ; Type Size(bytes) Minimum Maximum ------------------------------------------------------------------------------------------------------------ bool 1 char 1 -128 127 int 4 -2147483648 2147483647 uint 4 4294967295 short 2 -32768 32767 ushort 2 65535 long 4 -2147483648 2147483647 ulong 4 4294967295 ll 8 -9223372036854775808 9223372036854775807 ull 8 18446744073709551615 float 4 1.17549e-038 3.40282e+038 double 8 2.22507e-308 1.79769e+308 ldouble 8 2.22507e-308 1.79769e+308 ------------------------------------------------------------------------------------------------------------ int main ( int argc , char * argv [ ] ) QCoreApplication a ( argc , argv ) ; //printTypeInfo(); using namespace std ; /************************************************************************/ * 第一部分、往文件中写 /************************************************************************/ // 创建JSON对象 QJsonObject root ; // 创建fileList数组 QJsonObject obj ; obj [ "path" ] = "YangNaifeng" ; qint64 llData = 1 ; // LLONG_MAX; obj [ "size" ] = llData ; //最大15位 root . insert ( "fileList" , obj ) ; QJsonDocument doc ; doc . setObject ( root ) ; auto path = QCoreApplication :: applicationDirPath ( ) ; auto outJson = path + "/" + "sad.json" ; QDir dir ( path ) ; if ( dir . mkpath ( path ) ) QFile file ( outJson ) ; file . open ( QIODevice :: WriteOnly ) ; file . write ( doc . toJson ( ) ) ; file . close ( ) ; qCritical ( ) << QString :: fromStdWString ( L "创建文件夹失败!" ) ; /************************************************************************/ * 从文件中读 并解析 /************************************************************************/ QFile readFile ( outJson ) ; readFile . open ( QIODevice :: ReadOnly ) ; QByteArray data = readFile . readAll ( ) ; QJsonDocument docRead = QJsonDocument :: fromJson ( data ) ; if ( ! docRead . isNull ( ) && docRead . isObject ( ) ) { QJsonObject obj = docRead . object ( ) ; if ( obj . contains ( "fileList" ) && obj [ "fileList" ] . isObject ( ) ) { QJsonObject fileListObj = obj [ "fileList" ] . toObject ( ) ; QString path = fileListObj [ "path" ] . toString ( ) ; auto eDoubleType = QJsonValue :: Double ; cout << fileListObj [ "size" ] . type ( ) ; //QJsonValue::Double auto size = fileListObj [ "size" ] . toDouble ( ) ; qint64 nSize = QString :: number ( size , 'f' , 0 ) . toLongLong ( ) ; qDebug ( ) << "Path:" << path ; qDebug ( ) << "Size:" << size ; qDebug ( ) << "fileList not found" ; qDebug ( ) << "Invalid JSON document" ; return a . exec ( ) ; void printTypeInfo ( ) using namespace std ; // 设置表格样式 cout << left ; cout << setw ( 8 ) << "Type" ; cout << setw ( 22 ) << "Size(bytes)" ; cout << setw ( 22 ) << "Minimum" ; cout << setw ( 22 ) << "Maximum" ; cout << endl ; cout << "------------------------------------" ; cout << "------------------------------------" ; cout << "------------------------------------" ; cout << endl ; // bool cout << setw ( 8 ) << "bool" ; cout << setw ( 22 ) << sizeof ( bool ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) ; cout << endl ; // char cout << setw ( 8 ) << "char" ; cout << setw ( 22 ) << sizeof ( char ) ; cout << setw ( 22 ) << ( int ) CHAR_MIN ; cout << setw ( 22 ) << ( int ) CHAR_MAX ; cout << endl ; // int cout << setw ( 8 ) << "int" ; cout << setw ( 22 ) << sizeof ( int ) ; cout << setw ( 22 ) << INT_MIN ; cout << setw ( 22 ) << INT_MAX ; cout << endl ; // unsigned int cout << setw ( 8 ) << "uint" ; cout << setw ( 22 ) << sizeof ( unsigned int ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << UINT_MAX ; cout << endl ; // short cout << setw ( 8 ) << "short" ; cout << setw ( 22 ) << sizeof ( short ) ; cout << setw ( 22 ) << SHRT_MIN ; cout << setw ( 22 ) << SHRT_MAX ; cout << endl ; // unsigned short cout << setw ( 8 ) << "ushort" ; cout << setw ( 22 ) << sizeof ( unsigned short ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << USHRT_MAX ; cout << endl ; // long cout << setw ( 8 ) << "long" ; cout << setw ( 22 ) << sizeof ( long ) ; cout << setw ( 22 ) << LONG_MIN ; cout << setw ( 22 ) << LONG_MAX ; cout << endl ; // unsigned long cout << setw ( 8 ) << "ulong" ; cout << setw ( 22 ) << sizeof ( unsigned long ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << ULONG_MAX ; cout << endl ; // long long cout << setw ( 8 ) << "ll" ; cout << setw ( 22 ) << sizeof ( long long ) ; cout << setw ( 22 ) << LLONG_MIN ; cout << setw ( 22 ) << LLONG_MAX ; cout << endl ; // unsigned long long cout << setw ( 8 ) << "ull" ; cout << setw ( 22 ) << sizeof ( unsigned long long ) ; cout << setw ( 22 ) ; cout << setw ( 22 ) << ULLONG_MAX ; cout << endl ; // float cout << setw ( 8 ) << "float" ; cout << setw ( 22 ) << sizeof ( float ) ; cout << setw ( 22 ) << FLT_MIN ; cout << setw ( 22 ) << FLT_MAX ; cout << endl ; // double cout << setw ( 8 ) << "double" ; cout << setw ( 22 ) << sizeof ( double ) ; cout << setw ( 22 ) << DBL_MIN ; cout << setw ( 22 ) << DBL_MAX ; cout << endl ; // long double cout << setw ( 8 ) << "ldouble" ; cout << setw ( 22 ) << sizeof ( long double ) ; cout << setw ( 22 ) << LDBL_MIN ; cout << setw ( 22 ) << LDBL_MAX ; cout << endl ; cout << "------------------------------------" ; cout << "------------------------------------" ; cout << "------------------------------------" ;
1.
QJsonValue
存储整数是按照double类型存储的,即使是1这么一个很小的数。
2.
QJsonValue
的
toInt()
是提供了double到int的转换。而不是文件本身存的就是
int
类型的数据。
3.
QJsonValue
之所以没有
tolonglong()
的接口是因为
double
类型是有精度损失的。
double
类型的有效数字位数:15-16位数字,double类型的有效数字位数是15位还是16位,主要取决于浮点数的值:a. 对于绝对值在1.0和
2^53
之间的正常值,double类型一般能表示15位有效数字。b. 当浮点数接近0时,指数部位全部为0,此时有效数字位数可以达到16位。3. 当浮点数接近
2^53
时,指数部位为最大值,此时有效数字位数只有15位。
4.为啥Qt存整数到Json不是按整形存,而是以double类型存?
通过上面的介绍有两个关键点:
Javascript的数字存储使用了IEEE 754中规定的双精度浮点数数据类型,而这一数据类型能够安全存储 -(2^53-1) 到 2^53-1 之间的数值(包含边界值)。JSON 是 Javascript 的一个子集,所以它也遵守这个规则。
以下是rfc7159的说明:
Note that when such software is used, numbers that are integers and are in the range [-(2^53)+1, (2^53)-1] are interoperable in the sense that implementations will agree exactly on their numeric values.
这两个边界值可以通过 JavaScript 的 Number.MAX_SAFE_INTEGER 和 Number.MIN_SAFE_INTEGER 获取。
5. 对于特别大的数,保证精度首选字符串。