2014-03-13 32 views
1

我使用isalnum编写了一些代码来验证序列号是C中的字母数字。我写的代码假设isalnum输入是char。一切正常。但是,稍后查看isalnum后,我看到它需要输入为int。我的代码是否应该改变它的方式?C和C中的函数参数是char和int可互换的吗?

如果我确实需要改变,那么正确的方法是什么?我应该只声明一个int并将其设置为char并将其传递给isalnum?这被认为是糟糕的编程习惯吗?

在此先感谢。

#include <stdlib.h> 
#include <string.h> 
#include <stdbool.h> 


bool VerifySerialNumber(char *serialNumber) { 
int num; 
char* charPtr = serialNumber; 


if(strlen(serialNumber) < 10) { 
    printf("The entered serial number seems incorrect."); 
    printf("It's less than 10 characters.\n"); 
    return false; 
} 

while(*charPtr != '\0') { 
    if(!isalnum(*charPtr)) { 
    return false; 
    } 
    *charPtr++; 
} 
return true; 
} 


int main() { 
char* str1 = "abcdABCD1234"; 
char* str2 = "abcdef##"; 
char* str3 = "abcdABCD1234$#"; 
bool result; 

result = VerifySerialNumber(str1); 
printf("str= %s, result=%d\n\n", str1, result); 

result = VerifySerialNumber(str2); 
printf("str= %s, result=%d\n\n", str2, result); 

result = VerifySerialNumber(str3); 
printf("str= %s, result=%d\n\n", str3, result); 
return 0; 
} 

输出:

str= abcdABCD1234, result=1 

The entered serial number seems incorrect.It's less than 10 characters. 
str= abcdef##, result=0 

str= abcdABCD1234$#, result=0 

回答

8

你不需要去改变它。编译器会在将它传递给isalnum之前,将其隐式转换为int。像isalnum这样的函数采用int参数,因为像fgetc这样的函数返回值为int,这允许存在特殊值,如EOF

更新:正如其他人所说的,要小心你的负值char。您的C库可能的版本应该小心实施,以便处理负值而不会导致任何运行时错误。例如,glibc(标准C库的GNU实现)似乎通过在int参数中添加128来处理负数。 *但是,您不可能始终能够依靠isalnum(或其他任何<ctype.h>函数)安静地处理负数,因此养成不检查的习惯将是一个非常糟糕的主意。

*从技术上讲,它不添加128到参数本身,而是似乎使用参数作为一个指数到一个数组,开始于索引128,使得通过,比方说,-57将导致访问数组的索引71。但结果相同,因为array[-57+128](array+128)[-57]指向相同的位置。

+0

谢谢,@MikeHolt这被认为是不好的编程习惯还是没关系? – user1527227

+3

请注意签名与无符号值。如果你只使用0-127范围内的字符,那么没有问题。 –

+2

@ user1527227不,这不是糟糕的编程习惯。糟糕的编程习惯是将'int'传递给需要'char'的函数,而不采取预防措施以确保值不被截断。 –

2

一般它是细到char值传递给具有int的功能。它将被转换为具有相同值的int。这不是一个坏习惯。

但是isalnum和用于字符分类和转换的其他C函数存在特定问题。这就是,从ISO/IEC 9899:TC2 7.4/1(重点煤矿):

在所有情况下的参数为int其值应是 可表示为unsigned char或应等于 宏EOF的值。如果参数有任何其他值,则行为为 未定义。

所以,如果char是一个符号类型(这是依赖于实现),如果你遇到一个char与负值,那么它将把它传递给函数之前转换为int与负值。负数不能表示为unsigned char。可表示为unsigned char的数字是0UCHAR_MAX。因此,如果您传递任何负值而不是EOF碰巧发生的任何负值,那么您的行为就会不确定。

出于这个原因,你应该写你这样的代码在C:

if(!isalnum((unsigned char)*charPtr)) 

或C++中,你可能会喜欢:

if(!isalnum(static_cast<unsigned char>(*charPtr))) 

点是值得学习的,因为在第一次相遇,似乎荒谬:不通过char到字符函数

或者,在C++中,标头<locale>中有isalnum的双参数版本。此功能(及其朋友)确实需要输入char,因此您不必担心负值。你会惊讶地发现第二个参数是一个语言环境;-)

相关问题