определение структуры внутри main(), вызывающее ошибку сегментации

Нельзя ли определить структуру внутри main() . Я пробовал следующее только для получения ошибки сегментации:

#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#define TRUE 1


void main(int argc,char **argv)
{
struct test_struct
{

        char test_name[50];
        char summary_desc[200];
        char result[50];
};

struct suite_struct
{
        char suite_name[50];
        struct test_struct test[500];
        int test_count;
        int passed;
        int failed;
        int unresolved;
        int notrun;
}suite[500];

        int a,b;

        for (a=0;a<500;a++)
        {
                strcpy(suite[a].suite_name,"");
                for (b=0;b<500;b++)
                {
                        strcpy(suite[a].test[b].test_name,"");
                        strcpy(suite[a].test[b].summary_desc,"");
                        strcpy(suite[a].test[b].result,"");
                }
                suite[a].test_count=0;
                suite[a].passed=0;
                suite[a].failed=0;
                suite[a].unresolved=0;
                suite[a].notrun=0;
        }
}

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

#include <stdio.h>
#include <unistd.h>
#include <strings.h>
#define TRUE 1


struct test_struct 
{ 

        char test_name[50]; 
        char summary_desc[200]; 
        char result[50]; 
}; 

struct suite_struct 
{ 
        char suite_name[50]; 
        struct test_struct test[500]; 
        int test_count; 
        int passed; 
        int failed; 
        int unresolved; 
        int notrun; 
}suite[500]; 
void main(int argc,char **argv)
{

        int a,b;

        for (a=0;a<500;a++)
        {
                strcpy(suite[a].suite_name,"");
                for (b=0;b<500;b++)
                {
                        strcpy(suite[a].test[b].test_name,"");
                        strcpy(suite[a].test[b].summary_desc,"");
                        strcpy(suite[a].test[b].result,"");
                }
                suite[a].test_count=0;
                suite[a].passed=0;
                suite[a].failed=0;
                suite[a].unresolved=0;
                suite[a].notrun=0;
        }
}

Не уверен, почему это происходит. Для этого я использую компилятор Solaris SunStudio.


person tomkaith13    schedule 25.01.2012    source источник
comment
void main РААААААРРРРРРГГГГГХХХХХХ!   -  person pmg    schedule 25.01.2012
comment
Вам действительно нужно научиться пользоваться отладчиком. Вы пытались скомпилировать свою программу с включенными предупреждениями и отладочной информацией (где gcc означает -Wall -g)? Вы пользовались отладчиком? Мы могли бы найти вашу ошибку, но вам действительно следует научиться отлаживать ее самостоятельно....   -  person Basile Starynkevitch    schedule 25.01.2012
comment
void main незаконен. Структуры выглядят нормально. Но они великоваты для автоматического хранения.   -  person wildplasser    schedule 25.01.2012
comment
@Basile Starynkevitch: Я использовал компилятор cc. И отладчиком в Solaris является mdb. +0x7d(1, 80479ec, 0, 80479f1, 80479fe, 8047a12) Не знаете, что именно искать в этом ? Существует не так много руководств по использованию mdb для пользовательских программ.   -  person tomkaith13    schedule 25.01.2012
comment
Вам по-прежнему нужно научиться пользоваться компилятором (включая получение всех предупреждений, которые он может выдать) и как использовать отладчик (включая понимание его сообщений). Язык C небезопасен, и даже опытные программисты должны следить за предупреждениями компилятора и использовать отладчик.   -  person Basile Starynkevitch    schedule 25.01.2012
comment
@Basile Starynkevitch: Спасибо за совет ... Обязательно учту это в следующий раз.   -  person tomkaith13    schedule 25.01.2012


Ответы (5)


В первом примере suite живет в стеке, а во втором – в сегменте данных.

Поскольку suite довольно большой (~ 75 МБ), segfault почти наверняка возникает из-за того, что вашей программе не хватает места в стеке.

В большинстве случаев лучше размещать большие структуры данных в куче (используя malloc() и др.). Это также позволит выделить только то количество места, которое вам нужно, вместо того, чтобы всегда выделять место для 500 элементов.

person NPE    schedule 25.01.2012
comment
есть ли способ увеличить пространство стека? - person tomkaith13; 25.01.2012
comment
@tomkaith13 tomkaith13 это неправильный вопрос. Определите структуры за пределами main() или в заголовочном файле и выделите для них место в куче с помощью malloc(). - person Dan Fego; 25.01.2012
comment
@aix: я собирался опубликовать то же самое, но неправильно понял ваше имя пользователя как мое, и у меня был полный момент WTF. - person arx; 25.01.2012
comment
@aix: это просто какой-то грубый код (число 500), который я хотел написать ... и мне было лень создавать связанный список ... Урок усвоен !! :) Спасибо - person tomkaith13; 25.01.2012
comment
@aix: извините, что беспокою вас, но мне нужно узнать у вас больше подробностей о сбое. Я проверил размер стека Solaris, используя ulimit -Ss, который составляет около 10 МБ. Из схемы адресного пространства я знаю, что стек начинается с 0x8048000 и растет вниз. таким образом, стек должен заканчиваться на 0x76BE980.. но поскольку размер набора составляет 75 МБ, новое значение %esp равно 0x038b8364.. в этом проблема ?? я прав ?? - person tomkaith13; 26.01.2012

Можно объявить структуру внутри main. Но в вашей программе проблема связана с тем, что вы создаете 500 объектов этой структуры внутри основной функции. Каждый объект имеет размер около 15 КБ. Итак, 500 объектов требуют около 75 МБ. Попробуйте printf("size: %lu\n", sizeof suite);.

По умолчанию у вас не так много стека. Вы можете найти доступный стек с помощью команды ulimit -s. Он печатает доступный стек в КБ.

Вы можете использовать команду ulimit для увеличения стека. например ulimit -s 100000.

Лучшим подходом является динамическое выделение требуемой памяти с помощью malloc().

person Susam Pal    schedule 25.01.2012

Допустимо определить struct и объявить локальную переменную этого struct внутри любой функции, включая main.

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

person Basile Starynkevitch    schedule 25.01.2012

Структура, которую вы определяете вне main, является глобальной и неинициализированной, поэтому она попадет в сегмент .bss и будет инициализирована до 0 в начале выполнения. Структура, которую вы определяете внутри main, огромна и превышает максимальный размер стека (который составляет около 1-2 МБ в Linux и, возможно, в Solaris). Поскольку тот, что находится за пределами основного, не находится в стеке, похоже, он работает в этом случае, а не в другом.

person arsenm    schedule 25.01.2012
comment
Размер стека по умолчанию в SuSE составляет 8192 КБ. Однако все еще далеко от необходимых ~ 75M. - person Daniel Fischer; 25.01.2012
comment
На самом деле похоже, что я думал о винде на 1-2 МБ - person arsenm; 26.01.2012

В дополнение к ответам о стековом пространстве, malloc и неопределенном поведении. . .

Когда я попытался скомпилировать ваш код, я получил 3 предупреждения.

test.c:7:6: warning: return type of ‘main’ is not ‘int’
test.c: In function ‘main’:
test.c:32:17: warning: implicit declaration of function ‘strcpy’
test.c:32:17: warning: incompatible implicit declaration of built-in function ‘strcpy’

Возвращает int для main, а не void.

int main(int argc,char **argv)

В C заголовок для strcpy — это string.h, а не strings.h.

person Mike Sherrill 'Cat Recall'    schedule 25.01.2012