Большое спасибо.
Прошу ответить на два новых вопроса.
используйте беззнаковое смещение - size_t. У беззнаковых чисел переполнение однозначно определено и не приводит к undefined behavior:
Я думал, что при арифметических операциях с целыми числами есть только
один особый случай - деление на ноль. А всё остальное лишь переполнение
регистра, без каких-нибудь последствий. Не могли бы Вы пояснить, что Вы
подразумевали под этими своими словами "переполнение однозначно определено"?
Это первый мой вопрос.
Привожу написанную мной функцию преобразования строки в
off_t-число.
Для
off_t-чисел нет стандартных формата или функций преобразования, поэтому
самодельная. Сначала преобразует строку в
off_t-число, а затем полученное число
преобразует как бы в строку и сравнивает эту строку с исходной. На самом деле
другой строки нет, а есть посимвольное сравнение с исходной. Так отлавливает
переполнение.
// gcc parser_int.c -o parser_int.cgi -Wall -Werror -O3
// ./parser_int.cgi
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//------------------- my_a_to_off ---------------------
off_t
my_a_to_off(const char *str, int *err)
{
off_t s, d;
const char *p1, *p0;
int sig=0;
*err = 0;
p1=str;
while(*p1==' ') p1++;
if(*p1=='-'){ sig=1; p1++;}
else if(*p1=='+') p1++;
p0 = p1;
s=0;
while(*p1>='0' && *p1<='9'){
s = (s * 10) + ((*p1++) - '0');
}
if(sig==1) s=-s;
d=s;
if(d<0){
if(sig==0){ *err=1; return(s);}
while(p1>p0){ if(*(--p1) != ('0'-(d%10))){ *err=1; break;} d = d/10;}
}
else while(p1>p0){ if(*(--p1) != ('0'+(d%10))){ *err=1; break;} d = d/10;}
return(s);
}
//----------------- main -----------------------
int main()
{
off_t d;
int err;
const char *ptr;
char str[200];
while(1){
ptr = fgets(str, sizeof(str), stdin);
if(ptr==NULL) exit(0);
d = my_a_to_off(str, &err);
printf("%lld; err = %d\n", (long long int)d, err);
}
exit(0);
}
// 9223372036854775807 max off_t
//-9223372036854775808 min off_t
Рассмотрим кусок кода этой моей функции:
off_t s;
const char *p1, *p0;
while(*p1>='0' && *p1<='9'){
s = (s * 10) + ((*p1++) - '0');
}
Этот кусок преобразует строку в
off_t-число. Без проверки переполнения,
переполнение проверяется отдельно. Я знаю альтернативный код, вот он
(не опробован):
off_t s, d; // остальные int
s = 0;
while (isdigit(*p1)) {
digit = (*p1 - '0');
if (sign > 0) {
d = MAX_OFF_T / 10;
if(s > d){ err = 1; break;}
s = (s * 10);
if((MAX_OFF_T - s) < digit){ err = 1; break;}
s += digit;
} else {
d = MIN_OFF_T / 10;
if(s < d){ err = 1; break;}
s = (s * 10);
if((MIN_OFF_T + s) > (-digit)){ err = 1; break;}
s -= digit;
}
++p1;
}
Это хороший код, отлавливает "переполнение", но самого переполнения не бывает.
Тут комар носа не подточит, всё верно. Но надо знать константы, а в моей функции
их знать не надо. Я считал это моим преимуществом.
Когда я спрашивал: "Можно ли к указателю прибавить любое число?", то я
надеялся получить положительный ответ. Но ответ оказался скорее отрицательным,
чем положительным.
Теперь я спрашиваю: в этом моём куске кода, не альтернативном, а моём, а для него,
по замыслу, переполнение - это штатный режим, в нем переполняется не указатель, а
число, таится ли в этом моём куске кода какая-нибудь опасность? Это мой второй вопрос.