最近、最新リリースの Glibc(2.16) ソース コードを読んでいます。にいる間にstrtol
、次のコードを取得しました
/* some other code ... */
while (*nptr >= '0' && *nptr <= '9') {
unsigned long int digval = *nptr - '0';
if (result > LONG_MAX / 10 ||
(sign > 0 ? result == LONG_MAX / 10 && digval > LONG_MAX % 10
: (result == ((unsigned long int) LONG_MAX + 1) / 10 &&
digval > ((unsigned long int) LONG_MAX + 1) % 10))) {
errno = ERANGE;
return sign > 0 ? LONG_MAX : LONG_MIN;
}
result *= base;
result += digval;
++nptr;
}
エラーを判断するコードがERANGE
読みにくいかもしれませんが、わかりやすくするために、このように書き直します
unsigned long int
is_overflow(unsigned long int result, int sign, int digval) {
if (result > LONG_MAX / 10) {
goto error;
}
if (sign > 0) {
if (result == LONG_MAX / 10 && digval > LONG_MAX % 10)
goto error:
} else {
if (result == ((unsigned long int) LONG_MAX + 1) / 10 &&
digval > ((unsigned long int) LONG_MAX + 1) % 10)
goto error;
}
error:
errno = ERANGE;
return sign > 0 ? LONG_MAX : LONG_MIN;
}
そして、long-if ステートメントをテストするコードをいくつか書きます。
#include <stdio.h>
#define LONG_MAX 2147483647L
int main() {
int sign = 0;
int expr_val = 0;
int digval = '2';
/* without any modification */
expr_val = LONG_MAX / 10 && digval > LONG_MAX % 10;
printf("%d\n", expr_val);
expr_val = (unsigned long int) LONG_MAX + 1) / 10 &&
digval > ((unsigned long int) LONG_MAX + 1) % 10;
printf("%d\n", expr_val);
return 0;
}
これらの glibc の元のコードは、 と常に等しいため、result
と等しいかどうかを判断するようです。true
expr_val
true
私の質問は、なぜコードが に対してそのようなテストを追加するのかということresult
です
result > LONG_MAX / 10
連続オーバーフローを判断するのに十分ですか?そして、それが常に有効なデジタル値であることに関係なくresult == 1
、result == 0
なぜ著者はこれを行うのですか?