LINUX.ORG.RU

Си почему нельзя выделять большой многомерный массив в GCC

 


0

1

gcc 9.2.0

такой код падает (при запуске)

int w=1200;
int h=1200;
unsigned char array[w][h][2];

такой не падает

int w=1200;
int h=1200;
unsigned char *array;
array=(unsigned char*) malloc(2*w*h);
free(array);

я чтото фундаментальное упустил/забыл? В спеках Си какието ограничения на размер массива есть? В других компиляторах и другой версии GCC работает (но нужна именно эта версия для сборки)

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

Зачем ты вообще используешь VLA?

лень было делать ручной malloc и free (и руками перебирать массив по индексу, много кода проще было [][][] писать)

svv20624
() автор топика
Последнее исправление: svv20624 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

конечно. Это всё на усмотрение компилятора.

ясно спасибо

Попробуй добавить такой флаг: -fsplit-stack

да не, код кроссплатформенный лучше сделаю по нормальному

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

Объяви массив static, так он выделится в bss, а не на стеке.

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

чтото ты не то сказал, 1200x1200x2 это 2.8 Мегабайта

(очевидно мне не нужен статический размер надо создавать из полученных параметров массив)

очевидно что я таких мелочей про Си не помнил потому что редко пользуюсь и современные питоны/джаваскрипты где все динамически и на автомате уже делаешь массивы любого размера - вот так и написал в Си…

svv20624
() автор топика

Увеличь размер стека.

grem ★★★★★
()

В других компиляторах и другой версии GCC работает

Выделяйте «ручками». И да - есть беда (не Вы первый)

bugfixer ★★★★
()

Почему нельзя? Можно!

Только дело в том что в твоём примере ты используешь обычную локальную переменную. А память под них выделяется на стеке. Размер же стека ограничен. Можно конечно принудительно увеличить его, но это дело вкуса.

Когда ты используешь malloc то выделение памяти происходит на куче, макс размер ограничен твоим ОЗУ + размер файла подкачки - память уже веделенная для ОС и других процессов. То есть если у тебя на компе памяти больше терабайта, то можешь выделить массив на терабайт. Правда это только для 64-битных ОС и процессоров. В 32-битных макс. размер памяти для одной программы ограничен 3-4 Гигабайтами.

Можно выделить память через переменную типа static, это пнимерно как переменные типа dup в ассемблере. Под каждую из них в специальных сегментах выделяемых при загрузке твоей программы в память выделяется участок памяти. В старину существовали ограничения на размер этих сегментов (оттуда и название - сегмент) но сейчас там доступен максимальный размер ОЗУ как и в случае использования кучи.

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

Там реально есть проблемы, и реально исключительно с многомерными массивами. Если на практике проблема всплывает - проще один malloc, ну и поверх него уже. Мои 2 копейки.

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

C VLA везде должен падать.

Не зря на эту хрень есть предупреждения и в cppcheck и в clang.

И из ядра Linux вычистили это говно.

При VLA никак нельзя узнать упадёт программа или нет, так как нельзя узнать сколько свободного места осталось в стеке. И если нужно выделить больше чем осталось, то всё упадёт.

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

А Microsoft прямо сказал что не будет реализовывать VLA так как это говно небезопасное.

Это фича вообще опциональная в компиляторе С. То есть любой компилятор вправе её неподдерживать, и он всё равно будет соотвествовать стандарту.

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

C VLA везде должен падать.

С чего это вдруг? Этот код жрёт 2 МБ памяти. В стеке - 8. Я протестировал - у меня не падает на gcc 11.

При VLA никак нельзя узнать упадёт программа или нет, так как нельзя узнать сколько свободного места осталось в стеке. И если нужно выделить больше чем осталось, то всё упадёт.

И с malloc тоже нельзя узнать, упадёт программа или нет. По крайней мере в современном линуксе с умолчальными настройками.

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

Это фича вообще опциональная в компиляторе С. То есть любой компилятор вправе её неподдерживать, и он всё равно будет соотвествовать стандарту.

Я не знаю, опциональная ли она, но gcc её поддерживает, а значит она должна работать как положено.

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

Я не знаю, опциональная ли она, но gcc её поддерживает, а значит она должна работать как положено.

 Feature test macros for optional features
__STDC_NO_VLA__
    Indicates variable length arrays and variably modified types are not supported. 

https://en.cppreference.com/w/c/11

anonymous
()

(и руками перебирать массив по индексу, много кода проще было [][][] писать)

int w=1200;
int h=1200;
unsigned char (*array)[w][h];
array=(unsigned char (*)[w][h])malloc(2*w*h);
free(array);
SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от anonymous

Это фича вообще опциональная в компиляторе С

А их вообще-то из последних стандартов не выпилили нахрен? Или я с чем-то путаю?

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

Да, тут вообще чтобы аналог unsigned char array[w][h][2]; надо так делать

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

int main(void)
{
  int w=5;
  int h=4;
  int l=2;
  unsigned char (*array)[h][l] =(unsigned char (*)[h][l])malloc(w*h*l);
  {
    int cnt = 0;
    for(int w_i = 0; w_i < w; w_i++)
      for(int h_i = 0; h_i < h; h_i++)
        for(int l_i = 0; l_i < l; l_i++)
        {
          array[w_i][h_i][l_i] = cnt++;
        }
  }
  
  for(int w_i = 0; w_i < w; w_i++)
  {
    for(int h_i = 0; h_i < h; h_i++)
    {
      for(int l_i = 0; l_i < l; l_i++)
        printf("%d, ", array[w_i][h_i][l_i]);
      printf("\n");
    }
    printf("\n------------------\n");
  }
  free(array);
  return EXIT_SUCCESS; 
}
А каст в случае Си необязателен, да

SZT ★★★★★
()
Последнее исправление: SZT (всего исправлений: 1)
Ответ на: комментарий от hobbit

А их вообще-то из последних стандартов не выпилили нахрен? Или я с чем-то путаю?

Он был кандидат на включение в С++14. Но комитет в итоге отклонил предложение.

Из стандарта С вроде не собираются убирать. Но и не советуют использовать.

И вот мнение Линуса по этому поводу:https://lkml.org/lkml/2018/3/7/621

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

Ну или так:

#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>

void fill(const size_t N, double A[N][N])
{
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = 0; j < N; ++j) {
            A[i][j] = 10 * i + j;
        }
    }
}

void print(const size_t N, double A[N][N])
{
    for (size_t i = 0; i < N; ++i) {
        for (size_t j = 0; j < N; ++j) {
            printf("%4.1f ", A[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    for (size_t N = 5; N < 10; ++N) {
        double(*A)[N][N] = calloc(1, sizeof(*A));
        printf("Created matrix with size %d\n", (int)sizeof(*A));
        fill(N, *A);
        print(N, *A);
        free(A);
    }
    return 0;
}
AlexVR ★★★★★
()
Ответ на: комментарий от AlexVR

VLA используется, там нет никаких проверок. Будет падать при любом неправильном обращении и без предупреждений.

VLA зашквар.

меняем вместо N, на N+1 и ничего…

fill(N+1, *A);
print(N+1, *A);

https://gcc.godbolt.org/z/7eYqr6MEM

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

тоесть это в спеках Си ограничение?

конечно. Это всё на усмотрение компилятора.

А где оно описано? Нашёл только про Translation limits

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

у меня не падает на gcc 11.

на gcc 9.2.0 тоже не падает.

https://gcc.godbolt.org/z/oarxM4qzs

А падает наверное, потому что функции выше текущей тоже тратят стек. И когда вызывается эта функция, то стек уже закончился. Или там рекурсия где-то есть, или ещё что-нибудь.

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Может быть и так, я поверил топикстартеру.

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

VLA используется, там нет никаких проверок. Будет падать при любом неправильном обращении и без предупреждений.

Ну что сделать… что есть, то есть. Ну нет удобных и безопасных многомерных массивов в Си.

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

А падает наверное, потому что функции выше текущей тоже тратят стек. И когда вызывается эта функция, то стек уже закончился. Или там рекурсия где-то есть, или ещё что-нибудь.

да падает у меня мой код, в минимальном примере не падает очевидно

но да падает только при сборке gcc 9.2

как ты описал - много другого кода который может уменьшает размер стека

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

Можно сделать многомерный массив из одномерного при помощи адресной арифметики и обмазать его таким слоем синтаксического сахара каким хочется.

Более того, везде где многомерные массивы есть - они именно так и сделаны.

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

Зачем ты вообще используешь VLA?

Потому что он пишет на си. Отсутствие выразительности языка заставляет говнокодить.

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

Нет, быдлокодить заставляет отсутствие мозга!

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

За массивы на стеке вообще яйца отрывать надо!

Лучше задницу и голову поменять местами

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

Потому что он пишет на си. Отсутствие выразительности языка заставляет говнокодить.

и челам выше - пишу на Си раз в пол года, все остальное время на современных языках где не задумываешься и динамические массивы это дефолт, естественно забыл такую мелочь и запоминать естественно не буду проще спросить/загуглить еще раз если понадобиться в будущем

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

если лень - зачем тогда ваще C?

anonymous
()

В спеках Си какието ограничения на размер массива есть?

Ты просто идиот

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

Эти анонимные балаболы. Во-первых - там вла только потому, что он не засунул свои w/h в енум и в сишке нет const.

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

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

Какое отношение маздайка и маздайский дерьмокомпилятор имеет к си? Это дерьмо для рабов и даже в стандартный сишный огрызок оно никогда не умело и не умеет.

Это фича вообще опциональная в компиляторе С. То есть любой компилятор вправе её неподдерживать, и он всё равно будет соотвествовать стандарту.

То есть, жертва пропаганды, компилятор вообще может ничего не поддерживать и это будет соответствовать стандарту. Стандарт позволять создавать реализации, которые клали на стандарт.

Да и к тому же любой адекватный код на си всегда ссал на стандарт, а уж тем более используя стандарт ты можешь написать только лабу, хотя вряд ли ты даже её писал. А уж тем более ссылаясь на маздайку, которая не может ни в один стандарт. Особенно более-менее актуальный.

nonedi18
()
Ответ на: комментарий от fsb4000

Зачем вы все повторяете одну и ту же чушь. Падение никак не зависит от vla. Без вла всё так же будет падать при неправильном обращении без проверок.

Твой пример так же ничего не даст и без vla - значение N - это рантайм-значение.

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

Our team is happy to announce that C11 and C17 are becoming supported language versions in the MSVC compiler toolset starting with Visual Studio 2019 version 16.8 Preview 3!

For many years Visual Studio has only supported C to the extent of it being required for C++. Things are about to change now that a conformant token-based preprocessor has been added to the compiler. With the advent of two new compiler switches, /std:c11 and /std:c17, we are officially supporting the latest ISO C language standards.

https://devblogs.microsoft.com/cppblog/c11-and-c17-standard-support-arriving-in-msvc/

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

Ну и, что ты мне родил? Убогие своровали сишный огрызок, потому как в цпп подняли версию сишки. Это не является полноценной реализацией.

А уж тем более ссылаться на потуги маздайских клоунов. Ценность этим маня-заявлениям ноль. Эти клоуны уже сколько заявляют о какой-то поддержке цпп, но каждый раз они врут. Хотя ЦА привыкла жрать дерьмо с лопаты и им нормально.

Этого дерьма на годболте нет и проверить его невозможно.

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

Эти клоуны уже сколько заявляют о какой-то поддержке цпп, но каждый раз они врут.

Местами получше чем в GCC/Clang, и этих мест всё больше. И да, я не про самые последние фичи плюсов, а про те ещё времён C++98/03.

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

Местами получше чем в GCC/Clang, и этих мест всё больше.

Примеры. Кстати, у тебя настолько плохо с методичкой. gcc - это и есть си, потому как си - это гнуси. А шланг - это альтернативная реализация гнуси.

И да, я не про самые последние фичи плюсов, а про те ещё времён C++98/03.

Ахренительные мазы. Самый последние - это те, что младше 20 лет. Да, последние - это именно это. Чини методичку.

И да, 98/03 не является плюсами по определению. Ну и примеры ты не показал и не покажешь.

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

Подрывом попенсорц-фанбоя доволен

Примеры

Напиши на C++ что-нибудь сложнее HelloWorld-а — у тебя будет вагон таких примеров. Офигеешь, насколько Clang не умеет, например, в шаблоны.

Ну и примеры ты не показал и не покажешь.

Как и ты, собсна.

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

Я кстати жутко извиняюсь - я то поначалу подумал что господин @svv20624 side effect вот этого словил, но у него очевидно всё проще. В общем - «облажались мы», признаю ;)

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