次のコードは、g++ 4.1.1 および-Wall
.
int octalStrToInt(const std::string& s)
{
return strtol(s.c_str(), 0, 8);
}
strtol が a を返すため、警告が表示されることを期待していましたlong int
が、関数はプレーンのみを返しますint
。他のコンパイラがここで警告を発する可能性はありますか? この場合、戻り値を int にキャストすることをお勧めしますか?
最良のアプローチは次のとおりです。
long x = strtol(...); assert(x <= INT_MAX); return (int)x;
あなたが必要limits.h
とし、assert.h
にアクセスできない場合はboost::numeric_cast
、簡単な模倣を書くことができます。
template <typename T, typename S>
T range_check(const S &s) {
assert(s <= std::numeric_limits<T>::max());
assert(s >= std::numeric_limits<T>::min());
return static_cast<T>(s); // explicit conversion, no warnings.
}
return range_check<int>(strtol(some_value,0,8));
実際には、浮動小数点の宛先タイプでは機能しないため、これは少しごまかしです。min()
整数型の場合と同じ境界ではないため、 +/- に対してチェックする必要がありますmax()
。読者のための演習。
アサートを使用するか、その他のエラー処理を使用するかは、無効な入力に対して実際に何をしたいかによって異なります。
また、boost::lexical_cast
(8 進数を読み取る方法がわかりません) と stringstream もあります。たまたま C ライブラリ関数を持っている型ではなく、必要な型を読み取ります。
プラットフォームの「int」および「long int」データ型のサイズと範囲は同じであるため、ここでは警告は表示されません。アーキテクチャによっては、異なる場合があります。
奇妙なエラーから身を守るために、範囲チェックを使用してください。std::numeric_limits::min/max を使用することをお勧めします (「参考文献」を参照)。
範囲チェックの後、 static_cast または c-style キャストを安全に使用できます。
一方、std::stringstream クラスに実装されている同じ機能を利用できます。std::stringstream を使用した変換は、デフォルトでプラットフォーム セーフおよびタイプ セーフになります。
これらの警告をオンにするには、-Wconversion フラグが必要になる場合があります。ただし、 long -> intについては警告しません。これは、GCC と同じサイズであるためです (変換によって値が変更されることはありません)。しかし、たとえばlong -> shortに変換すると、
バグの可能性を隠すだけなので、単純にキャストすることはお勧めできません。そのようなキャストが値を変更してコンパイラをなだめることがないことを確認したら、問題ありません。
最新のコンパイラのほとんどは、構成した警告レベルに応じて、変換と切り捨ての可能性について警告します。警告レベル 4 の MSVC で。
ベスト プラクティスは、関数から long を返し、呼び出し元のコードに変換の処理方法を決定させることです。Let_Me_Be で示唆されているように、少なくとも strtol から返される値が、戻る前に int に収まることを確認してください。