一些常见函数的内部实现(原)
Wentao Sun
1. 子串查找:
/* strtok_s */
/*
* strtok_s, wcstok_s ;
* uses _Context to keep track of the position in the string.
*/
_SAFECRT__EXTERN_C
char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context);
#if _SAFECRT_USE_INLINES
__inline
char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context)
{
unsigned char *str;
const unsigned char *ctl = (const unsigned char *)_Control;
unsigned char map[32];
int count;
/* validation section */
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL);
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL);
_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL);
/* Clear control map */
for (count = 0; count < 32; count++)
{
map[count] = 0;
}
/* Set bits in delimiter table */
do {
map[*ctl >> 3] |= (1 << (*ctl & 7));
} while (*ctl++);
/* If string is NULL, set str to the saved
* pointer (i.e., continue breaking tokens out of the string
* from the last strtok call) */
if (_String != NULL)
{
str = (unsigned char *)_String;
}
else
{
str = (unsigned char *)*_Context;
}
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets str to point to the terminal
* null (*str == 0) */
while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)
{
str++;
}
_String = (char *)str;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *str != 0 ; str++ )
{
if (map[*str >> 3] & (1 << (*str & 7)))
{
*str++ = 0;
break;
}
}
/* Update context */
*_Context = (char *)str;
/* Determine if a token has been found. */
if (_String == (char *)str)
{
return NULL;
}
else
{
return _String;
}
}
#endif
/* wcstok_s */
_SAFECRT__EXTERN_C
wchar_t * __cdecl wcstok_s(wchar_t *_String, const wchar_t *_Control, wchar_t **_Context);
#if _SAFECRT_USE_INLINES
__inline
wchar_t * __cdecl wcstok_s(wchar_t *_String, const wchar_t *_Control, wchar_t **_Context)
{
wchar_t *token;
const wchar_t *ctl;
/* validation section */
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL);
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL);
_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL);
/* If string==NULL, continue with previous string */
if (!_String)
{
_String = *_Context;
}
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets string to point to the terminal null. */
for ( ; *_String != 0 ; _String++)
{
for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
;
if (*ctl == 0)
{
break;
}
}
token = _String;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *_String != 0 ; _String++)
{
for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
;
if (*ctl != 0)
{
*_String++ = 0;
break;
}
}
/* Update the context */
*_Context = _String;
/* Determine if a token has been found. */
if (token == _String)
{
return NULL;
}
else
{
return token;
}
}
#endif
/*
* strtok_s, wcstok_s ;
* uses _Context to keep track of the position in the string.
*/
_SAFECRT__EXTERN_C
char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context);
#if _SAFECRT_USE_INLINES
__inline
char * __cdecl strtok_s(char *_String, const char *_Control, char **_Context)
{
unsigned char *str;
const unsigned char *ctl = (const unsigned char *)_Control;
unsigned char map[32];
int count;
/* validation section */
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL);
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL);
_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL);
/* Clear control map */
for (count = 0; count < 32; count++)
{
map[count] = 0;
}
/* Set bits in delimiter table */
do {
map[*ctl >> 3] |= (1 << (*ctl & 7));
} while (*ctl++);
/* If string is NULL, set str to the saved
* pointer (i.e., continue breaking tokens out of the string
* from the last strtok call) */
if (_String != NULL)
{
str = (unsigned char *)_String;
}
else
{
str = (unsigned char *)*_Context;
}
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets str to point to the terminal
* null (*str == 0) */
while ((map[*str >> 3] & (1 << (*str & 7))) && *str != 0)
{
str++;
}
_String = (char *)str;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *str != 0 ; str++ )
{
if (map[*str >> 3] & (1 << (*str & 7)))
{
*str++ = 0;
break;
}
}
/* Update context */
*_Context = (char *)str;
/* Determine if a token has been found. */
if (_String == (char *)str)
{
return NULL;
}
else
{
return _String;
}
}
#endif
/* wcstok_s */
_SAFECRT__EXTERN_C
wchar_t * __cdecl wcstok_s(wchar_t *_String, const wchar_t *_Control, wchar_t **_Context);
#if _SAFECRT_USE_INLINES
__inline
wchar_t * __cdecl wcstok_s(wchar_t *_String, const wchar_t *_Control, wchar_t **_Context)
{
wchar_t *token;
const wchar_t *ctl;
/* validation section */
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Context, EINVAL, NULL);
_SAFECRT__VALIDATE_POINTER_ERROR_RETURN(_Control, EINVAL, NULL);
_SAFECRT__VALIDATE_CONDITION_ERROR_RETURN(_String != NULL || *_Context != NULL, EINVAL, NULL);
/* If string==NULL, continue with previous string */
if (!_String)
{
_String = *_Context;
}
/* Find beginning of token (skip over leading delimiters). Note that
* there is no token iff this loop sets string to point to the terminal null. */
for ( ; *_String != 0 ; _String++)
{
for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
;
if (*ctl == 0)
{
break;
}
}
token = _String;
/* Find the end of the token. If it is not the end of the string,
* put a null there. */
for ( ; *_String != 0 ; _String++)
{
for (ctl = _Control; *ctl != 0 && *ctl != *_String; ctl++)
;
if (*ctl != 0)
{
*_String++ = 0;
break;
}
}
/* Update the context */
*_Context = _String;
/* Determine if a token has been found. */
if (token == _String)
{
return NULL;
}
else
{
return token;
}
}
#endif
2. 使用strsafe.h时需要注意将其放到其他string操作头文件的后面,以免不必要的编译错误。
可以参考:http://www.programfan.com/club/showtxt.asp?id=235904
我今天在编译的适合也碰到过这个问题。
再次强调,使用strsafe.h最好是放在cpp文件中,而非头文件中。
在微软的tchar.h中明确的有个#error put strsafe.h behind thar.h。 strsafe.h被要求放在tchar.h的后面。如果不这样,会得到一堆很奇怪的错误。