LINUX.ORG.RU

Названия для размеров часто используемых буферов

 , , ,


0

3

Приветствую всех!

Сделал так:

#define GIANT_SIZE     1024*32
#define HUGE_SIZE      1024*16 
#define LARGE_SIZE     1024*8 
#define BIG_SIZE       1024 
#define MIDDLE_SIZE    512
#define MEDIUM_SIZE    256
#define SMALL_SIZE     128 
#define LITTLE_SIZE    64 
#define TINY_SIZE      32 

Стильно получилось?

Часто требуется, например, считать строку из файла, и чтобы не плодить магических констант, вместо 512 писать MIDDLE_SIZE

...
while (!feof(fp))
{
    char buff[MIDDLE_SIZE];
    fgets(buff, MIDDLE_SIZE, fp);
    buff[MIDDLE_SIZE-1]='\0';
    char* line = str_dup(buff);
    str_trim(line);
...

Например, загрузка матрицы из файла формата (нарочно зашумленный пробелами и tab-ами):



DIM1=	3
	
  DIM2 = 7


{
   	 0.935    0.674    -1.687    0.468  2.436   -1.743  0.275

   	 0.111    0.346    0.368   0.907    -7.346     -0.235    -0.139  
0.436    -0.134    -1.047    0.879    -1.051  -0.367         -0.196

}
	

выглядит вот так

void matrix_load( MATRIX* A, const char* fileName)
{
    FILE* fp;
    bool b_is_dim1_read=false;
    bool b_is_dim2_read=false;
    unsigned int dim1, dim2;
    bool begin=false;
    bool end = false;
    int row_count = 0;


    if ((fp = fopen(fileName,"r")) == NULL)
    {
      fprintf(stderr,"File '%s' open failed\n", fileName);
      enter_pause();
      exit(EXIT_FAILURE);
    }
    else
    {
        while (!feof(fp))
        {
            char buff[MIDDLE_SIZE];
            fgets(buff, MIDDLE_SIZE, fp);
            buff[MIDDLE_SIZE-1]='\0';
            char* line = str_dup(buff); // 
            str_trim(line);  // обрезаем '\t','\v', '\f', '\n', '\r', ' '      

            if (0==strlen(line)) // если после обрезки строка пустая, то пропускаем обработку
            {
                free(line);
                continue;
            }
            
            if (line[0] == 'D' && line[1] == 'I' && line[2]== 'M') // если встретилось "DIM"
            {
                Tokens* dim  = tokens_new(2);
                string_split(dim, line, "="); // разбиваем строку по '='
                

                if (line[3]== '1' || line[3]== '2') // DIM1 или DIM2
                {
                    errno = 0;
                    char *endptr;
                    unsigned int d = strtoul(dim->array[1]->data, &endptr, 10);
                    
                    if (*endptr != '\0' || errno !=0 || d==0 || d>30) // не более 30x30
                    {
                        fprintf(stderr,"Error: dimension wrong '%s'\n", dim->array[1]->data);
                        tokens_free(dim);
                        free(line);
                        enter_pause();
                        exit(EXIT_FAILURE);
                    }
                    
                    switch (line[3])
                    {
                    case '1':
                        dim1 = d;
                        b_is_dim1_read = true;
                        break;

                    case '2':
                        dim2 = d;
                        b_is_dim2_read = true;
                        break;

                    }
                }
                
                 // если все размерности считаны, то выделяем память для матрицы
                if (b_is_dim1_read && b_is_dim2_read)
                {
                    matrix_create(A, dim1, dim2);
                }

                tokens_clear(dim);
                tokens_free(dim);
            }

            

            if (line[0] =='{') { begin=true; free(line); continue; } // признак начала значений матрицы
            if (line[0] =='}') { end=true;   free(line); continue; }
            if (begin && !end)
            {
                //printf("%s\n", line);
                Tokens* row  = tokens_new(dim2); // по кол-ву элементов в строке
                string_split(row, line, " ");

                // если столбцов недостаточно или строк больше заявленных
                if (dim2 != row->size || row_count >= dim1)
                {
                    fprintf(stderr,"Error: Invalid file format '%s'\n", fileName);
                    enter_pause();
                    exit(EXIT_FAILURE);
                }

                // заполнение строки матрицы
                for (int j=0; j<dim2; ++j)
                {
                    
                    errno = 0;
                    char *endptr;
                    double value = strtod(row->array[j]->data, &endptr);
                    if (*endptr != '\0' || errno != 0 || 10 < strlen(row->array[j]->data) ) //не более 10-значное число
                    {
                        fprintf(stderr,"Error: wrong value '%s'\n", row->array[j]->data);
                        tokens_free(row);
                        free(line);
                        matrix_free(A);
                        enter_pause();
                        exit(EXIT_FAILURE);
                    }
                    matrix_set_elem(A, row_count, j,  value);
                }
                row_count++;
                tokens_clear(row);
                tokens_free(row);
            }


            free(line);
        }
        fclose(fp);

        if (row_count != dim1) // недочитали заявленные dim1 строк
        {
            fprintf(stderr,"Error: Invalid file format '%s'\n", fileName);
            enter_pause();
            exit(EXIT_FAILURE);
        }
    }

}

Функция str_dup:

char *str_dup(char const *in)
{
    if ( !in ) return NULL;
    size_t len = strlen(in);
    char *out = malloc(len+1);
    strncpy(out, in, len+1);
    return out;
}

Буду рад услышать отзывы о стиле.



Последнее исправление: Gyros (всего исправлений: 1)

Ответ на: комментарий от anonymous

как раз хомячков не запутывает - хомячки все в курсе, что в компах 1024

запутывает вот таких вот скандинавских умников, пиарящихся в научном болотце

капча: медведь в солнцезащитных очках

anonymous
()
Ответ на: комментарий от vbr

Был у нас такой тимлид. Итальянская забастовка с тысячами бессмысленных констант привела к тому, что он наоборот возрадовался! Вот теперь KpacuBo! Потом хвастался, как он научил безграмотных австралопитеков писать изящный код.

anonymous
()
Ответ на: комментарий от Gyros

Спасибо! Исправил:

придётся ещё раз исправлять :-)

char *str_dup(char const *in)
{
    if ( !in ) return NULL;   /// тут assert, потому как IRL NULL не должен передаваться
    /// (можно даже аттрибут вкорячить nonull)
    /// и отдать дублированную пустую строку "\0"

    size_t len = strlen(in);
    /// тут нужна проверку на размер len (смотрим man malloc)

    char *out = malloc(len+1);

    /// а вот тут точно не assert - тут резко падаем в exit
    assert( (out != NULL)  && "Memory allocation failed!");

    /// иначе тут с -DNDEBUG релизная версия грохнется самостоятельно
    strncpy(out, in, len+1);
    return out;
}
MKuznetsov ★★★★★
()
Ответ на: комментарий от cobold

Поддерживаю твоё осуждение автора, однако ты тоже написал ерунду. 8*KB ещё хуже чем 1024*8 (за словом KB может скрываться так называемый десятичный килобайт), хорошо 8192. Код с аллокацией - норм, аллоцируется не весь буфер а только под размер прочитанного, который мы заранее не знаем.

firkax ★★★★★
()
Последнее исправление: firkax (всего исправлений: 1)

Часто требуется, например, считать строку из файла, и чтобы не плодить магических констант, вместо 512 писать MIDDLE_SIZE

Твоё MIDDLE_SIZE это и есть магическая константа.

Причём тут стиль не знаю, но то что ты сделал - очень плохо. Ничего кроме вреда (именно так) ты от этого не получишь.

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

можно все написать и на С и на С++, тут выбирать тебе и твоей команде - на чем удобнее, эффективнее, забавнее и т.п. …

можно и совочком яму вырыть, можно и экскаватор пригнать, зависит от размера ямы, денег, времени, фана, пива и т.д. )

x905 ★★★★★
()

#define GIANT_SIZE 1024*32
...
#define TINY_SIZE 32

sed 's/^\([^ ]*\) \(.*\)_SIZE\(.*\)$/\1 SIZE_\2\3/g'
superuser ★★★★☆
()
Ответ на: комментарий от firkax

Про килобайты. Тебя тоже облачные провайдеры покусали? Кто ещё оперативку десятичными килобайтами считает? В остальном прав. Хотя пустопорожние копирование осуждаю. Такты не бесплатные

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

Макросы (включая константы и защиту заголовочных файлов от повторного включения), глобальные переменные, структуры, перечисления, объединения, функции следует именовать как префикс_название, например, если ты пишешь GIMP, то функция должна называться gimp_some_function. Иначе есть вероятность конфликта с чужим кодом.

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

Меня не покусали, по представь ты смотришь чей-то исходник и там написано 8*KB. Понятно конечно что разумно было бы если б он был 1024, но поскольку доверять разумности других программистов не стоит, придётся лезть куда-то в другой хедер и искать где же объявлен этот KB. А если сразу написано 8192 то никуда лезть не придётся.

Хотя пустопорожние копирование осуждаю

Ну тут три варианта - либо копирование, либо перерасход памяти, либо самописный аллокатор который сможет выделять такие куски (заранее неизвестного размера) без оверхедов (и ещё неизвестно какой там дальше код, возможно третий вариант не подойдёт).

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

У конфликта есть только вероятность, а вот у захламления экрана лишними буквами при твоём подходе - практически гарантия. Где-то префиксы и правда желательны (в основном это касается библиотек, которые ты не знаешь куда подключат), но совсем не везде.

firkax ★★★★★
()
Ответ на: комментарий от MKuznetsov
  1. len не нужно проверять, т.к. в malloc-е стоит len+1.

Если подать пустую строку, то вернется созданный пустой дубликат.

  1. Если же входная строка NULL, то и вернуть должны NULL. Ошибкой в самой str_dup это считаться не должно.

В библиотечной strdup С23

If an error occurs, a null pointer is returned and errno might be set. 

Внутри str_dup м.б. только одна ошибка от malloc-а.

Поэтому исправленная версия:

char *str_dup(char const *in)
{
    if ( !in ) return NULL;
    size_t len = strlen(in);
    char *out = malloc(len+1);
    if (!out)
    {
       fprintf(stderr, "str_dup error: Memory allocation failed!\n");
       exit(EXIT_FAILURE);
    }
    strncpy(out, in, len+1);
    return out;
}
Gyros
() автор топика
Последнее исправление: Gyros (всего исправлений: 1)
Ответ на: комментарий от Gyros

В библиотечной strdup С23

раз уж тебя потянуло на std_dup, значит библиотечный тебя уже категорично не устраивает своим чем-то :-) Например тем что может вернут NULL. Определись чем именно или всё-же используй обычный strdup()

assert() в проверке аргументов можно вернуть. В реальной жизни передача NULL в параметр strdup - в 90% ошибка где-то выше и нарушение контракта

strncpy внутри заменить на memcpy - размеры буферов и длина строки известны, лишний раз проверять на \0 не надо

len не нужно проверять, т.к. в malloc-е стоит len+1

раз уж взялся чтобы хорошо и всюду секурно: (паранойя, фантастично, но) len+1 может переполнить size_t.

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

«значит библиотечный тебя уже категорично не устраивает своим чем-то»

  • у меня -std=c11

«В реальной жизни передача NULL в параметр strdup - в 90% ошибка где-то выше и нарушение контракта»

  • согласен

Переделал:

char *str_dup(char const *in)
{
    assert(in && "str_dup error: Passing a non-existent string");
    //if ( !in ) return NULL;
    size_t len = strlen(in);
    char *out = malloc(len+1);
    if (!out)
    {
       fprintf(stderr, "str_dup error: Memory allocation failed!\n");
       exit(EXIT_FAILURE);
    }
    //strncpy(out, in, len+1);
    memcpy(out, in, len+1);
    return out;
}
Gyros
() автор топика
Ответ на: комментарий от Gyros

можно даже вертеть про реальную жизнь :-)

если не суровый эмбед с мизером памяти и аллокаторами от buggle, то:

malloc может вернуть NULL только если передан овер-дохрена размер. Больше чем PTRDIFF_MAX или 2^46

даже когда памяти нет, но можно отдать что-то виртуальное - будет отдано нечто виртуальное. А скорее приклад будет прибит OOM-киллером, ещё до момента проверки ptr==NULL

если сможешь без хаков сделать test-case который заворачивает в ветвление !out то ok. Иначе оформлять как #ifdef WITH_PARANOYA :-)

PS/ к теме топика: проблем и приколов много..а вы себе ещё и новых сущностей добавляете, которые надо помнить и контролировать

MKuznetsov ★★★★★
()

Предлагаю названия для часто встречающихся размеров буферов

#define AA_CUP 32
#define A_CUP 64
#define B_CUP 128
#define C_CUP 256
//....
#define JJ_CUP 64*1024

LongLiveUbuntu ★★★★★
()

Вы загружаете данные и не возвращаете результат операции - успешно ли вы загрузили? А если загрузили не все, это успешно или нет? Как обрабатываете ситуацию, когда «не влезло»?

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

Что у Вас представляет assert hendler? Почему надо именно assert использовать, а не пробовать выделить меньшее количество памяти или вернуть ошибку выделения памяти и обработать ее в месте вызова функции?

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

Проекты разные. Библиотека utils.h одна на все проекты. Размеры определены в ней.

Вот и пропиши префикс UTILS на все define в этом самом utils.h, может в конкретной ситуации это и не будет важно, а в других поможет.

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

Почему надо именно assert использовать, а не пробовать выделить меньшее количество памяти

Потому что это функция strdup

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

Любые проблемы с загрузкой - это ошибка и останов.

Если ничего не произошло, то загрузка успешная.

Ситуацию «когда не влезло» не обрабатываю, потому что ее никогда не будет; не будет таких данных.

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

Ситуацию «когда не влезло» не обрабатываю, потому что ее никогда не будет; не будет таких данных.

Это первая серия сериала.

СПОЙЛЕР к последней, кто ещё такой сериал не смотрел, не читайте:


















































> Ну кто ж знал, что оно вот так прилетит?! Оно ж не могло… не должно было! Всех нештатных ситуаций невозможно предусмотреть!
CrX ★★★★★
()
Последнее исправление: CrX (всего исправлений: 1)

Как-то слишком неинтуитивно, лучше снизить количество констант (чтобы не разбираться кто больше small или litte) и использовать более понятные имена:

#define YOUR_MUM_SIZE     1024*32
#define MY_PENIS_SIZE     1024
#define YOUR_PENIS_SIZE     128
ugoday ★★★★★
()
Ответ на: комментарий от ugoday

Вот я так и знал, что «этого» дойдет..

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

Что можно сделать на С++, чего нельзя сделать на С?

Если говорить не отходя от темы, то enum class. И не засорять глобальное пространство.

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

Возвращаемое значение: NULL – если не удалость выделить память под новую строку или скопировать строку на которую указывает аргумент str. Указатель на дублирующую строку.

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

ну и в assert не вываливается, а просто возвращает NULL

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

Например, может где-то оказаться в коде

#define BUFFER_STORAGE_SIZE 1000000U
#define BUFFER_COUNT BUFFER_STORAGE_SIZE/BUFFER_LARGE_SIZE

Чему будет равно BUFFER_COUNT?

Ну и может оказаться, что код будет использован в проекте где строгая проверка на знак переменных. В этом случае надо четко указывать является ли константа знаковой или нет.

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

Memory overcommit отключается одним sysctl-ом, также не работает при заданном ulimit и имеется не во всех ОС. Поэтому считать, что malloc никогда не вернет NULL можно, но это справедливо только в контролируемом окружении.

vbr ★★★★
()
Последнее исправление: vbr (всего исправлений: 1)
Для того чтобы оставить комментарий войдите или зарегистрируйтесь.