C++ namespaceを使って既存のテンプレートをカスタマイズ
namespace をうまく使うと既存のテンプレートをきれいにカスタマイズすることができます
std::map と文字列の自然順比較
std::map のキーに std::string を使うとその要素はデフォルトでは辞書順に並びます
これを自然順に並ぶようにするにはどうすればいいでしょうか
std::map の要素の並び順はテンプレートの第三引数である less 関数によるので基本的にはここに文字列の自然順比較をする less を指定すればいいだけです
ただ、単純にそういったクラスを用意するだけでは std::map のテンプレート引数に毎回そのクラスを指定することになってしまって使うときにいちいち面倒ですね
template<class T> struct natural_order_less : public std::less<T> {}; template<> struct natural_order_less<std::string> : public std::binary_function<std::string,std::string,bool> { bool operator()( const std::string& lhs, const std::string& rhs ) const { return ( &lhs[0] == &rhs[0] ) ? false : ( strcmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 ); } }; template<> struct natural_order_less<std::wstring> : public std::binary_function<std::wstring,std::wstring,bool> { bool operator()( const std::wstring& lhs, const std::wstring& rhs ) const { return ( &lhs[0] == &rhs[0] ) ? false : ( wcscmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 ); } };
std::map<std::string,int,natural_order_less<std::string> > aaa; . . . for( std::map<std::string,int,natural_order_less<std::string> >::iterator p = aaa.begin(); p != aaa.end(); ++p ){ ... }
こういうときには専用の namespace を作ると少し便利になりますよ
文字列の自然順比較専用の namespace を作りましょう
namespace natural_order { template<class T> struct less : public std::less<T> {}; template<> struct less<std::string> : public std::binary_function<std::string,std::string,bool> { bool operator()( const std::string& lhs, const std::string& rhs ) const { return ( &lhs[0] == &rhs[0] ) ? false : ( strcmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 ); } }; template<> struct less<std::wstring> : public std::binary_function<std::wstring,std::wstring,bool> { bool operator()( const std::wstring& lhs, const std::wstring& rhs ) const { return ( &lhs[0] == &rhs[0] ) ? false : ( wcscmp_by_natural_order( &lhs[0], &rhs[0] ) < 0 ); } }; template<class _key_type, class _value_type, class _less_type = less<_key_type>, class _allocator_type = std::allocator<std::pair<const _key_type, _value_type> > > struct map : public std::map<_key_type,_value_type,_less_type,_allocator_type> {}; }
こうして専用の namespace を作っておくと使うときも簡単でしかも自然順比較の map であることも一目瞭然になります
natural_order::map<std::string,int> aaa; . . . for( natural_order::map<std::string,int>::iterator p = aaa.begin(); p != aaa.end(); ++p ){ ... }
簡単ですね
std::map のキー文字列の大文字小文字を無視
今度は std::map のキー文字列の大文字小文字を無視したいとしましょう
aaa["aaA"] = 1; aaa["aaa"] = 2; aaa["AAA"] = 3;
出力
aaA
このようなときはどうすればいいでしょうか
#include <string> #include <map> namespace case_insensitive { template<class T> struct less : public std::less<T> {}; template<> struct less<std::string> : public std::binary_function<std::string,std::string,bool> { bool operator()( const std::string& lhs, const std::string& rhs ) const { return ( &lhs[0] == &rhs[0] ) ? false : ( stricmp( &lhs[0], &rhs[0] ) < 0 ); } }; template<> struct less<std::wstring> : public std::binary_function<std::wstring,std::wstring,bool> { bool operator()( const std::wstring& lhs, const std::wstring& rhs ) const { return ( &lhs[0] == &rhs[0] ) ? false : ( wcsicmp( &lhs[0], &rhs[0] ) < 0 ); } }; template<class _key_type, class _value_type, class _less_type = less<_key_type>, class _allocator_type = std::allocator<std::pair<const _key_type, _value_type> > > struct map : public std::map<_key_type,_value_type,_less_type,_allocator_type> {}; }
#include <windows.h> inline void OutputDebugStringA( const std::string& s ){ OutputDebugStringA( &s[0] ); } int main(){ case_insensitive::map<std::string,int> aaa; aaa["aaa"] = 1; aaa["AAA"] = 2; aaa["aaA"] = 3; for( case_insensitive::map<std::string,int>::iterator p = aaa.begin(); p != aaa.end(); ++p ){ OutputDebugString( p->first ); OutputDebugString( "\n" ); } return 0; }
出力
aaa
std::map のキー文字列を大文字に
今度は std::map のキー文字列を大文字にしたいとしましょう
bbb[L"BbB"] = 1; bbb[L"bBB"] = 2; bbb[L"BBb"] = 3;
出力
BBB
このようなときはどうすればいいでしょうか
#include <string> template<typename _plain_type, typename _signed_type = _plain_type,typename _unsigned_type = _plain_type> struct signed_unsigned { typedef _plain_type plain_type; typedef _signed_type signed_type; typedef _unsigned_type unsigned_type; }; template<> struct signed_unsigned<char> : public signed_unsigned<char,signed char,unsigned char> {}; template<> struct signed_unsigned<signed char> : public signed_unsigned<char,signed char,unsigned char> {}; template<> struct signed_unsigned<unsigned char> : public signed_unsigned<char,signed char,unsigned char> {}; template<class char_type> struct ctype { static char_type toupper ( char_type c ){ return ( char_type )::toupper ( signed_unsigned<char_type>::unsigned_type( c )); }; static char_type tolower ( char_type c ){ return ( char_type )::tolower ( signed_unsigned<char_type>::unsigned_type( c )); }; }; template<> struct ctype<wchar_t> { static wchar_t toupper ( wchar_t wc ){ return ( wchar_t )::towupper ( wc ); }; static wchar_t tolower ( wchar_t wc ){ return ( wchar_t )::towlower ( wc ); }; }; namespace upper_case { template<class char_type> struct char_traits : public std::char_traits<char_type> { // 本当はこの3つだけでいいんだけど仮想関数じゃないから他のも全部オーバーライドするよ static void assign( char_type& lhs, const char_type& rhs ){ lhs = ctype<char_type>::toupper ( rhs ); } static bool eq( const char_type& lhs, const char_type& rhs ){ return ( ctype<char_type>::toupper ( lhs ) == ctype<char_type>::toupper ( rhs )); } static bool lt( const char_type& lhs, const char_type& rhs ){ return ( ctype<char_type>::toupper ( lhs ) < ctype<char_type>::toupper ( rhs )); } // static int compare( const char_type* lhs, const char_type* rhs, size_t cch ){ int result = 0; while( cch > 0 ){ if( !eq( *lhs, *rhs )){ result = lt( *lhs, *rhs ) ? -1 : +1; break; } ++lhs; ++rhs; --cch; } return result; } static size_t length( const char_type* s ){ const char_type* p = s; while( !eq( *p, char_type())){ ++p; } return p - s; } static char_type* copy( char_type* d, const char_type* s, size_t cch ){ return copy( d, cch, s, cch ); } static char_type* copy( char_type* d, size_t cch_d, const char_type* s, size_t cch_s ){ char_type* p = d; while( cch_s > 0 ){ assign( *p, *s ); ++p; ++s; --cch_s; } return d; } static const char_type* find( const char_type* p, size_t cch, const char_type& ch ){ const char_type* result = 0; while( cch > 0 ){ if( eq( *p, ch )){ result = p; break; } ++p; --cch; } return result; } static char_type* move( char_type* d, const char_type* s, size_t cch ){ return move( d, cch, s, cch ); } static char_type* move( char_type* d, size_t cch_d, const char_type* s, size_t cch_s ){ char_type* p = d; if(( p > s )&&( p < s + cch_s )){ p += cch_s; s += cch_s; while( cch_s > 0 ){ assign( *--p, *--s ); --cch_s; } } else{ while( cch_s > 0 ){ assign( *p, *s ); ++p; ++s; --cch_s; } } return d; } static char_type* assign( char_type* d, size_t cch, char_type ch ){ char_type* p = d; while( cch > 0 ){ assign( *p, ch ); ++p; --cch; } return d; } // これは大文字小文字に関係ないから基底クラスのでいいよ //static char_type to_char_type( const int_type& _Meta ); //static int_type to_int_type( const char_type& ch ); //static bool eq_int_type( const int_type& lhs, const int_type& rhs ); //static int_type eof(); //static int_type not_eof( const int_type& _Meta ); }; typedef std::basic_string<char,char_traits<char>,std::allocator<char> > string; typedef std::basic_string<wchar_t,char_traits<wchar_t>,std::allocator<wchar_t> > wstring; }
#include <windows.h> #include <map> inline void OutputDebugStringA( const upper_case::string& s ){ OutputDebugStringA( &s[0] ); } inline void OutputDebugStringW( const upper_case::wstring& s ){ OutputDebugStringW( &s[0] ); } int main(){ std::map<upper_case::string,int> aaa; aaa["aaa"] = 1; aaa["AAA"] = 2; aaa["aaA"] = 3; for( std::map<upper_case::string,int>::iterator p = aaa.begin(); p != aaa.end(); ++p ){ OutputDebugString( p->first ); OutputDebugString( "\n" ); } std::map<upper_case::wstring,int> bbb; bbb[L"BbB"] = 1; bbb[L"bBB"] = 2; bbb[L"BBb"] = 3; for( std::map<upper_case::wstring,int>::iterator p = bbb.begin(); p != bbb.end(); ++p ){ OutputDebugStringW( p->first ); OutputDebugString( "\n" ); } return 0; }
出力
AAA BBB
std::map のキー文字列を小文字に
今度は std::map のキー文字列を小文字にしたいとしましょう
bbb[L"BbB"] = 1; bbb[L"bBB"] = 2; bbb[L"BBb"] = 3;
出力
bbb
このようなときはどうすればいいでしょうか
もちろん大文字のときと同じように小文字用の char_traits<> を書くのですが、毎回 char_traits のメソッドをいくつも、しかも同じ内容のものを書くのもばかばかしいですよね
ここは char_traits<> の assign, eq, lt だけを書けばいいようにしてみましょう
struct char_traits_exception { static void out_of_range(){ __debugbrak(); } }; template<class char_type, class traits_class = std::char_traits<char_type>, class exception_class = char_traits_exception> struct char_traits : public traits_class { // この3つは派生クラスで定義させるよ //static void assign( char_type& lhs, const char_type& rhs ); //static bool eq( const char_type& lhs, const char_type& rhs ); //static bool lt( const char_type& lhs, const char_type& rhs ); // コピー/比較に関するメソッドは traits_class に指定されたクラスの assign, eq, lt を使う static int compare( const char_type* lhs, const char_type* rhs, size_t cch ){ int result = 0; while( cch > 0 ){ if( !traits_class::eq( *lhs, *rhs )){ result = traits_class::lt( *lhs, *rhs ) ? -1 : +1; break; } ++lhs; ++rhs; --cch; } return result; } static size_t length( const char_type* s ){ const char_type* p = s; while( !traits_class::eq( *p, char_type())){ ++p; } return p - s; } static char_type* copy( char_type* d, const char_type* s, size_t cch ){ return copy( d, cch, s, cch ); } static char_type* copy( char_type* d, size_t cch_d, const char_type* s, size_t cch_s ){ if( cch_d < cch_s ){ out_of_range(); } char_type* p = d; while( cch_s > 0 ){ traits_class::assign( *p, *s ); ++p; ++s; --cch_s; } return d; } static const char_type* find( const char_type* p, size_t cch, const char_type& ch ){ const char_type* result = 0; while( cch > 0 ){ if( traits_class::eq( *p, ch )){ result = p; break; } ++p; --cch; } return result; } static char_type* move( char_type* d, const char_type* s, size_t cch ){ return move( d, cch, s, cch ); } static char_type* move( char_type* d, size_t cch_d, const char_type* s, size_t cch_s ){ if( cch_d < cch_s ){ out_of_range(); } char_type* p = d; if(( p > s )&&( p < s + cch_s )){ p += cch_s; s += cch_s; while( cch_s > 0 ){ traits_class::assign( *--p, *--s ); --cch_s; } } else{ while( cch_s > 0 ){ traits_class::assign( *p, *s ); ++p; ++s; --cch_s; } } return d; } static char_type* assign( char_type* d, size_t cch, char_type ch ){ char_type* p = d; while( cch > 0 ){ traits_class::assign( *p, ch ); ++p; --cch; } return d; } // コピー/比較に関係ないメソッドは基底クラスのでいいよ //static char_type to_char_type( const int_type& _Meta ); //static int_type to_int_type( const char_type& ch ); //static bool eq_int_type( const int_type& lhs, const int_type& rhs ); //static int_type eof(); //static int_type not_eof( const int_type& _Meta ); };
そうすると小文字用の char_traits<> はこんなに簡単になります
namespace lower_case { template<class char_type> struct char_traits : public ::char_traits<char_type,char_traits<char_type> > { static void assign( char_type& lhs, const char_type& rhs ){ lhs = ctype<char_type>::tolower ( rhs ); } static bool eq( const char_type& lhs, const char_type& rhs ){ return ( ctype<char_type>::tolower ( lhs ) == ctype<char_type>::tolower ( rhs )); } static bool lt( const char_type& lhs, const char_type& rhs ){ return ( ctype<char_type>::tolower ( lhs ) < ctype<char_type>::tolower ( rhs )); } }; typedef std::basic_string<char,char_traits<char>,std::allocator<char> > string; typedef std::basic_string<wchar_t,char_traits<wchar_t>,std::allocator<wchar_t> > wstring; }
#include <windows.h> #include <map> inline void OutputDebugStringA( const lower_case::string& s ){ OutputDebugStringA( &s[0] ); } inline void OutputDebugStringW( const lower_case::wstring& s ){ OutputDebugStringW( &s[0] ); } int main(){ std::map<lower_case::string,int> aaa; aaa["aaa"] = 1; aaa["AAA"] = 2; aaa["aaA"] = 3; for( std::map<lower_case::string,int>::iterator p = aaa.begin(); p != aaa.end(); ++p ){ OutputDebugString( p->first ); OutputDebugString( "\n" ); } std::map<lower_case::wstring,int> bbb; bbb[L"BbB"] = 1; bbb[L"bBB"] = 2; bbb[L"BBb"] = 3; for( std::map<lower_case::wstring,int>::iterator p = bbb.begin(); p != bbb.end(); ++p ){ OutputDebugStringW( p->first ); OutputDebugString( "\n" ); } return 0; }
出力
aaa bbb
余談
ところで、テストコードのところにそれぞれの namespace の string 用にいくつも OutputDebugString を定義していたのにお気づきでしたでしょうか
inline void OutputDebugStringA( const std::string& s ){ OutputDebugStringA( &s[0] ); } inline void OutputDebugStringW( const std::wstring& s ){ OutputDebugStringW( &s[0] ); } inline void OutputDebugStringA( const upper_case::string& s ){ OutputDebugStringA( &s[0] ); } inline void OutputDebugStringW( const upper_case::wstring& s ){ OutputDebugStringW( &s[0] ); } inline void OutputDebugStringA( const lower_case::string& s ){ OutputDebugStringA( &s[0] ); } inline void OutputDebugStringW( const lower_case::wstring& s ){ OutputDebugStringW( &s[0] ); }
このように同じものをいくつも書くのは無駄ですね
これは引数としてそれぞれの namespace にある string を受け取ろうとしているところから来る問題なので、共通の基底クラスである std::basic_string<> を受け取るようにすれば std::string でも upper_case::string でも lower_case::string でも使えるようになりますよ
template<class _char_type,class _traits_type,class _allocator_type> inline void OutputDebugStringA( const std::basic_string<_char_type,_traits_type,_allocator_type>& s ){ OutputDebugStringA( &s[0] ); } template<class _char_type,class _traits_type,class _allocator_type> inline void OutputDebugStringW( const std::basic_string<_char_type,_traits_type,_allocator_type>& s ){ OutputDebugStringW( &s[0] ); }
同じコードがといえば、下記に自然順比較のコードの一例を載せておきますが、マルチバイトとワイドキャラクタでほとんど同じですね
本当はこういうときこそテンプレートですよ
// 自然順比較:文字列中の数字の並びを1つの数字として比較します // 単純な辞書順の様に aaa1, aaa10, aaa2 などとはならず、aaa1, aaa2, aaa10 となります int strcmp_by_natural_order( const char* s1, const char* s2 ){ #if ( TEMPORARY_STRING_SIZE == 0 ) size_t cch1 = strlen( s1 ); size_t cch2 = strlen( s2 ); size_t cchTemp = cch1 + cch2; size_t cbTemp = sizeof( char ) * ( cchTemp+1 ); char* temp1 = ( char* )malloc( cbTemp ); char* temp2 = ( char* )malloc( cbTemp ); #else // TEMPORARY_STRING_SIZE char temp1[TEMPORARY_STRING_SIZE]; char temp2[TEMPORARY_STRING_SIZE]; #endif // TEMPORARY_STRING_SIZE int result = 0; size_t ns1 = 0; size_t ns2 = 0; do{ if( isdigit(( unsigned char )s1[ns1] ) && isdigit(( unsigned char )s2[ns2] )){ // 文字列中の数字部分は数値として比較する char* i1 = temp1; char* i2 = temp2; size_t ni1 = 0; size_t ni2 = 0; // 整数部分の切り出し do{ i1[ni1] = s1[ns1]; ++ni1; ++ns1; }while( s1[ns1] && isdigit(( unsigned char )s1[ns1] )); do{ i2[ni2] = s2[ns2]; ++ni2; ++ns2; }while( s2[ns2] && isdigit(( unsigned char )s2[ns2] )); // 短い方の前に 0 を入れて桁を揃える if( ni1 < ni2 ){ size_t m = ni2 - ni1; for( size_t i = 0; i < ni1; ++i ){ i1[m+ni1-i-1] = i1[ni1-i-1]; } {for( size_t i = 0; i < m; ++i ){ i1[i] = '0'; }} ni1 += m; } else if( ni1 > ni2 ){ size_t m = ni1 - ni2; for( size_t i = 0; i < ni2; ++i ){ i2[m+ni2-i-1] = i2[ni2-i-1]; } {for( size_t i = 0; i < m; ++i ){ i2[i] = '0'; }} ni2 += m; } if(( s1[ns1] == '.' )||( s2[ns2] == '.' )){ // 小数部分の切り出し if( s1[ns1] == '.' ){ do{ i1[ni1] = s1[ns1]; ++ni1; ++ns1; }while( s1[ns1] && isdigit(( unsigned char )s1[ns1] )); } else{ i1[ni1] = '.'; ++ni1; } if( s2[ns2] == '.' ){ do{ i2[ni2] = s2[ns2]; ++ni2; ++ns2; }while( s2[ns2] && isdigit(( unsigned char )s2[ns2] )); } else{ i2[ni2] = '.'; ++ni2; } // 短い方の後ろに 0 を入れて桁を揃える if( ni1 < ni2 ){ size_t m = ni2 - ni1; for( size_t i = 0; i < m; ++i ){ i1[ni1] = '0'; ++ni1; } } else if( ni1 > ni2 ){ size_t m = ni1 - ni2; for( size_t i = 0; i < m; ++i ){ i2[ni2] = '0'; ++ni2; } } } i1[ni1] = '\0'; i2[ni2] = '\0'; result = strncmp( &i1[0], &i2[0], ni1 ); } else{ // 数字以外の文字は普通に比較する result = ( int )( unsigned char )s1[ns1] - ( int )( unsigned char )s2[ns2]; while( s1[ns1] && s2[ns2] && !result ){ if( isdigit(( unsigned char )s1[ns1] ) || isdigit(( unsigned char )s2[ns2] )){ break; } unsigned int c1 = ( unsigned int )( unsigned char )s1[ns1]; unsigned int c2 = ( unsigned int )( unsigned char )s2[ns2]; if( _ismbblead( c1 ) && _ismbblead( c2 )){ c1 = ( c1 << 8 ) | ( unsigned int )( unsigned char )s1[ns1+1]; c2 = ( c2 << 8 ) | ( unsigned int )( unsigned char )s2[ns2+1]; ns2 += 2; ns1 += 2; } else if( _ismbblead( c1 )){ c1 = ( c1 << 8 ) | ( unsigned int )( unsigned char )s1[ns1+1]; ++ns2; ns1 += 2; } else if( _ismbblead( c2 )){ c2 = ( c2 << 8 ) | ( unsigned int )( unsigned char )s2[ns2+1]; ns2 += 2; ++ns1; } else{ ++ns2; ++ns1; } result = ( int )( c1 - c2 ); } } }while( s1[ns1] && s2[ns2] && !result ); if(( s1[ns1] != s2[ns2] )&&( !s1[ns1] || !s2[ns2] )){ unsigned int c1 = ( unsigned int )( unsigned char )s1[ns1]; unsigned int c2 = ( unsigned int )( unsigned char )s2[ns2]; if( _ismbblead( c1 )){ c1 = ( c1 << 8 ) | ( unsigned int )( unsigned char )s1[ns1+1]; } else if( _ismbblead( c2 )){ c2 = ( c2 << 8 ) | ( unsigned int )( unsigned char )s2[ns2+1]; } if( !result ){ result = ( int )( c1 - c2 ); } } #if ( TEMPORARY_STRING_SIZE == 0 ) free( temp2 ); free( temp1 ); #endif // TEMPORARY_STRING_SIZE return result; }
int wcscmp_by_natural_order( const wchar_t* s1, const wchar_t* s2 ){ #if ( TEMPORARY_STRING_SIZE == 0 ) size_t cch1 = wcslen( s1 ); size_t cch2 = wcslen( s2 ); size_t cchTemp = cch1 + cch2; size_t cbTemp = sizeof( wchar_t ) * ( cchTemp+1 ); wchar_t* temp1 = ( wchar_t* )malloc( cbTemp ); wchar_t* temp2 = ( wchar_t* )malloc( cbTemp ); #else // TEMPORARY_STRING_SIZE wchar_t temp1[TEMPORARY_STRING_SIZE]; wchar_t temp2[TEMPORARY_STRING_SIZE]; #endif // TEMPORARY_STRING_SIZE int result = 0; size_t ns1 = 0; size_t ns2 = 0; do{ if( iswdigit( s1[ns1] ) && iswdigit( s2[ns2] )){ // 文字列中の数字部分は数値として比較する wchar_t* i1 = temp1; wchar_t* i2 = temp2; size_t ni1 = 0; size_t ni2 = 0; // 整数部分の切り出し do{ i1[ni1] = s1[ns1]; ++ni1; ++ns1; }while( s1[ns1] && iswdigit( s1[ns1] )); do{ i2[ni2] = s2[ns2]; ++ni2; ++ns2; }while( s2[ns2] && iswdigit( s2[ns2] )); // 短い方の前に 0 を入れて桁を揃える if( ni1 < ni2 ){ size_t m = ni2 - ni1; for( size_t i = 0; i < ni1; ++i ){ i1[m+ni1-i-1] = i1[ni1-i-1]; } {for( size_t i = 0; i < m; ++i ){ i1[i] = L'0'; }} ni1 += m; } else if( ni1 > ni2 ){ size_t m = ni1 - ni2; for( size_t i = 0; i < ni2; ++i ){ i2[m+ni2-i-1] = i2[ni2-i-1]; } {for( size_t i = 0; i < m; ++i ){ i2[i] = L'0'; }} ni2 += m; } if(( s1[ns1] == L'.' )||( s2[ns2] == L'.' )){ // 小数部分の切り出し if( s1[ns1] == L'.' ){ do{ i1[ni1] = s1[ns1]; ++ni1; ++ns1; }while( s1[ns1] && iswdigit( s1[ns1] )); } else{ i1[ni1] = L'.'; ++ni1; } if( s2[ns2] == L'.' ){ do{ i2[ni2] = s2[ns2]; ++ni2; ++ns2; }while( s2[ns2] && iswdigit( s2[ns2] )); } else{ i2[ni2] = L'.'; ++ni2; } // 短い方の後ろに 0 を入れて桁を揃える if( ni1 < ni2 ){ size_t m = ni2 - ni1; for( size_t i = 0; i < m; ++i ){ i1[ni1] = L'0'; ++ni1; } } else if( ni1 > ni2 ){ size_t m = ni1 - ni2; for( size_t i = 0; i < m; ++i ){ i2[ni2] = L'0'; ++ni2; } } } i1[ni1] = L'\0'; i2[ni2] = L'\0'; result = wcsncmp( &i1[0], &i2[0], ni1 ); } else{ // 数字以外の文字は普通に比較する result = s1[ns1] - s2[ns2]; while( s1[ns1] && s2[ns2] && !result && !iswdigit( s1[ns1] ) && !iswdigit( s2[ns2] )){ result = s1[ns1] - s2[ns2]; ++ns2; ++ns1; } } }while( s1[ns1] && s2[ns2] && !result ); if(( s1[ns1] != s2[ns2] )&&( !s1[ns1] || !s2[ns2] )){ if( !result ){ result = ( int )(( unsigned int )s1[ns1] - ( unsigned int )s2[ns2] ); } } #if ( TEMPORARY_STRING_SIZE == 0 ) free( temp2 ); free( temp1 ); #endif // TEMPORARY_STRING_SIZE return result; }
それから malloc じゃなくて _alloca/_malloca とかにした方がいいですね