LINUX.ORG.RU

[СИ] Как работать с off_t числами.

 


0

1

[СИ] Как работать с off_t числами.

Язык СИ
ОС UNIX

Не знаю штатных средств работы с off_t числами, надежных.
Ниже две самодельных функции для преобразования
off_t -> строка и обратно.

Вопрос-1.
Существуют ли надежные штатные средства?

Вопрос-2.
В функции my_ato_off() (см. ниже) не знаю, как правильно
отловить выход из диапазона. Там есть закомментированная
строка, которая предположительно может отловить ошибку.
И при опробовании да, отлавливает. Но всегда ли, при
любой ли строке символов?

Кто знает прошу ответить.



#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

//   gcc forum_off_t.c -o forum_off_t.cgi
//   ./forum_off_t.cgi

//------------------- my_ato_off ---------------------
off_t
my_ato_off(const char *buf)

{
    off_t  s, sm;
    const char *p1;
    int sig=0;

    p1=buf;
    while(*p1==' ') p1++;
    if(*p1=='-'){ sig=1; p1++;}
    s=0;
    while(*p1>='0' && *p1<='9'){
        sm=(s*10)+((*p1)-'0');
        //if(sm<s) return(-1);
        s=sm;
        p1++;
    }
    if(sig>0) s=-s;
    return(s);
}

//----------------- my_off_toa -------------------------

int my_off_toa(off_t  d, char *str, int Sstr)

{
    char *p1, buf[30];
    int  k, sig=0;

    p1=buf;
    if(d<0) sig=1;
    if(sig==0) do{ k=d%10; *p1++=('0'+k);} while((d=d/10)!=0);
    else do{ k=d%10; *p1++=('0'-k);} while((d=d/10)!=0);

    if((p1-buf)>=(Sstr-sig)){ *str=0; return(-1);}
    if(sig>0) *str++ = '-';
    while(p1>buf){ *str++ = *(--p1);}
    *str=0;

    return(0);
}

//--------------- main ---------------

int main()

{
    char *p, buf[100], str[21];
    off_t  s;
    int    k;

    printf("\n---------------------------------------\n");

    while(1){
        p=fgets(buf, sizeof(buf), stdin);
        if(p==NULL){
            printf("p==NULL\n");
            printf("\n---------------------------------------\n");
            continue;
        }
        printf("1. buf=%s\n", buf);

        s=my_ato_off(buf);
        printf("2. s  =%lld\n", s);

        k=my_off_toa(s, str, sizeof(str));
        printf("3. str=%s; (%d)\n", str, k);

        k=atoi(buf);
        printf("4. k  =%d\n", k);
        printf("\n---------------------------------------\n");
    }
    exit(0);
}




Ответ на: комментарий от Obey-Kun

Вот например:
printf(«2. s =%lld\n», s);
где s типа off_t.
Безопасно ли это?
Всегда ли sizeof(off_t)=sizeof(long long)?
Есть еще нестандартный %j для типа off_t. Но он не стандартный.

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

> Вот например:

printf(«2. s =%lld\n», s);

где s типа off_t.


Безопасно ли это?



Нет, потому что...

Всегда ли sizeof(off_t)=sizeof(long long)?


... размер off_t не обязан быть равным размеру long long.

Relan ★★★★★
()

Вот мой скриптик, который считает трафик за определенный период по логам squid'а. Работает с 64-битными off_t без проблем.

Главное, не забывайте в самом начале файла указать #define _FILE_OFFSET_BITS 64

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от oleg_2

Всегда ли sizeof(off_t)=sizeof(long long)?

при программирование на C таких вопросов много возникает. Я просто вставляю assert(sizeof(off_t)==sizeof(long long)).

true_admin ★★★★★
()
Ответ на: комментарий от oleg_2

printf(«2. s =%lld\n», s);

где s типа off_t.

Безопасно ли это?

Всегда ли sizeof(off_t)=sizeof(long long)?

Есть еще нестандартный %j для типа off_t. Но он не стандартный.


Скорее всего, off_t можно скастовать к intmax_t.

printf(«2. s = » PRIdMAX «\n», (intmax_t) s);

Изучай /usr/include/inttypes.h.

akk ★★★★★
()

off64_t стопудово будет 64-битным :)

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от arsi

Да. Убедили, но не совсем еще.
Нужно еще обратное преобразование. Желательно с возвратом
ошибки. Например, с одной 64-машины копируем Гига-файл на
другую 32-машину. При сбое надо передать указатель на
«контрольную точку» файла. Для простоты в текстовом виде.
И если вторая машина не способна понять число, пусть хотя бы
выдаст ошибку.

Вы написали, и здесь написано
http://www.opennet.ru/man.shtml?topic=sscanf&category=3&russian=0
«Обратите внимание на то, что тип long long не является типом ANSI C.»
Две маленькие функции оправдают возможные потом неприятности,
если они будут безотказны.
Думаю, что вопрос спорный.

Есть еще вопрос-2. Как детектировать ошибку в функции.
Ели упомянутый в начале способ не подтвердится, то можно другой,
похуже, но тоже ничего. Если иметь хорошие константы, например,
такую:
const char offmax=«9223372036854775807»; (0x7FFFFFFFFFFFFFFF)
то можно просто посимвольно сравнить входной текст с такой константой.
По моему, должно сработать. Придется привязываться к sizeof(off_t).

oleg_2
() автор топика
Ответ на: комментарий от oleg_2

Да используйте вы уже явные 64-битные константы. Замените off_t на off64_t, а всякие lseek'и на lseek64...

Eddy_Em ☆☆☆☆☆
()
Ответ на: комментарий от oleg_2

всё верно, в с89 нет long long. хотя поддерживается многими компиляторами как расширение.

при разборе проверять на переполнение можно или в цикле перед умножением и сложением, или, если гарантируется корректность строки (содержит только десятичные цифры и начинается с '1'-'9' или содержит только '0'), в самом начале, перед преобразованием:

if (strlen(str) > strlen(offmax) || strcmp(str, offmax) > 0) {
	/* overflow */
}

arsi ★★★★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.