我在C中编写了一个函数,它将字符串转换为整数并返回整数.当我调用该函数时,我也希望它告诉我字符串是不是有效数字.在过去,当发生此错误时,我返回-1,因为我不需要将字符串转换为负数.但现在我希望它将字符串转换为负数,那么报告错误的最佳方法是什么?
如果我不清楚这一点:我不希望此函数向用户报告错误,我希望它将错误报告给调用该函数的代码.("报告"可能是错误的用词...)
这是代码:
s32 intval(const char *string) { bool negative = false; u32 current_char = 0; if (string[0] == '-') { negative = true; current_char = 1; } s32 num = 0; while (string[current_char]) { if (string[current_char] < '0' || string[current_char] > '9') { // Return an error here.. but how? } num *= 10; num += string[current_char] - '0'; current_char++; } if (negative) { num = -num; } return num; }
Michael Burr.. 35
有几种方法.所有人都有他们的优点和缺点.
让函数返回错误代码并传入指向某个位置的指针以返回结果.关于这一点的好处是没有结果的重载.不好的是你不能直接在表达式中使用函数的实际结果.
Evan Teran提出了一个变体,它使调用者传递一个指向成功变量的指针(如果调用者不关心,可以选择为NULL)并返回函数的实际值.这样做的好处是,当调用者在错误结果中使用默认值或者知道函数不能失败时,允许函数直接在表达式中使用.
使用特殊的"sentinel"返回值来指示错误,例如负数(如果正常返回值不能为负数),INT_MAX
或者INT_MIN
如果良好值不能达到极值.有时为了获得更详细的错误信息,需要查询另一个函数(例如GetLastError()
)或全局变量(例如errno
).如果您的返回值没有无效值,并且一般被许多人视为不良格式,则此方法无效.
使用此技术的示例函数是getc(),如果到达文件末尾或遇到错误,则返回EOF.
让函数永远不会直接返回错误指示,但要求调用者查询另一个函数或全局函数.这类似于VB的" On Error Goto Next
"模式的工作原理 - 它几乎被普遍认为是一种糟糕的方式.
另一种方法是拥有"默认"值.例如,atoi()
函数与函数intval()
几乎完全相同,当它无法转换任何字符时将返回0(它与函数的不同之处在于它消耗字符进行转换,直到它到达字符串的末尾或者不是数字的字符).
这里明显的缺点是,判断实际值是否已转换或是否已传递垃圾可能很棘手atoi()
.
我不是这种处理错误的忠实粉丝.
我会更新,因为其他选项在我脑海中浮现......
有几种方法.所有人都有他们的优点和缺点.
让函数返回错误代码并传入指向某个位置的指针以返回结果.关于这一点的好处是没有结果的重载.不好的是你不能直接在表达式中使用函数的实际结果.
Evan Teran提出了一个变体,它使调用者传递一个指向成功变量的指针(如果调用者不关心,可以选择为NULL)并返回函数的实际值.这样做的好处是,当调用者在错误结果中使用默认值或者知道函数不能失败时,允许函数直接在表达式中使用.
使用特殊的"sentinel"返回值来指示错误,例如负数(如果正常返回值不能为负数),INT_MAX
或者INT_MIN
如果良好值不能达到极值.有时为了获得更详细的错误信息,需要查询另一个函数(例如GetLastError()
)或全局变量(例如errno
).如果您的返回值没有无效值,并且一般被许多人视为不良格式,则此方法无效.
使用此技术的示例函数是getc(),如果到达文件末尾或遇到错误,则返回EOF.
让函数永远不会直接返回错误指示,但要求调用者查询另一个函数或全局函数.这类似于VB的" On Error Goto Next
"模式的工作原理 - 它几乎被普遍认为是一种糟糕的方式.
另一种方法是拥有"默认"值.例如,atoi()
函数与函数intval()
几乎完全相同,当它无法转换任何字符时将返回0(它与函数的不同之处在于它消耗字符进行转换,直到它到达字符串的末尾或者不是数字的字符).
这里明显的缺点是,判断实际值是否已转换或是否已传递垃圾可能很棘手atoi()
.
我不是这种处理错误的忠实粉丝.
我会更新,因为其他选项在我脑海中浮现......
那么,.NET在Int32.TryParse中处理它的方式是返回成功/失败,并使用pass-by-reference参数传回解析后的值.同样可以在C中应用:
int intval(const char *string, s32 *parsed) { *parsed = 0; // So that if we return an error, the value is well-defined // Normal code, returning error codes if necessary // ... *parsed = num; return SUCCESS; // Or whatever }
一种常见的方法是将指针传递给成功标志,如下所示:
int my_function(int *ok) { /* whatever */ if(ok) { *ok = success; } return ret_val; }
这样叫:
int ok; int ret = my_function(&ok); if(ok) { /* use ret safely here */ }
编辑:这里的示例实现:
s32 intval(const char *string, int *ok) { bool negative = false; u32 current_char = 0; if (string[0] == '-') { negative = true; current_char = 1; } s32 num = 0; while (string[current_char]) { if (string[current_char] < '0' || string[current_char] > '9') { // Return an error here.. but how? if(ok) { *ok = 0; } } num *= 10; num += string[current_char] - '0'; current_char++; } if (negative) { num = -num; } if(ok) { *ok = 1; } return num; } int ok; s32 val = intval("123a", &ok); if(ok) { printf("conversion successful\n"); }
os风格的全局errno变量也很受欢迎.使用errno.h
.
如果errno不为零,则出现问题.
这是errno的手册页参考.