LINUX.ORG.RU

C + random + array + segfault

 , , ,


0

1
#include <stdio.h>

main() {
    srand(time(NULL));
    int arr[9999999];
    int i;
    for(i=0; i<9999999; i++) {
        arr[i] = rand() % 99999999;
        printf("%d \n", arr[i]);
    }
}

решил откопать книгу по Си. Первый пример, ловлю segfault. Что не так? вывод strace:

execve("./a.out", ["./a.out"], [/* 47 vars */]) = 0
brk(0)                                  = 0x87a1000
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7716000
access("/etc/ld.so.preload", R_OK)      = -1 ENOENT (No such file or directory)
open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
fstat64(3, {st_mode=S_IFREG|0644, st_size=111260, ...}) = 0
mmap2(NULL, 111260, PROT_READ, MAP_PRIVATE, 3, 0) = 0xb76fa000
close(3)                                = 0
open("/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\0\227\1\0004\0\0\0"..., 512) = 512
fstat64(3, {st_mode=S_IFREG|0755, st_size=1790836, ...}) = 0
mmap2(NULL, 1591836, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0xb7575000
mprotect(0xb76f3000, 4096, PROT_NONE)   = 0
mmap2(0xb76f4000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_DENYWRITE, 3, 0x17e) = 0xb76f4000
mmap2(0xb76f7000, 10780, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0xb76f7000
close(3)                                = 0
mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0xb7574000
set_thread_area({entry_number:-1 -> 6, base_addr:0xb75746c0, limit:1048575, seg_32bit:1, contents:0, read_exec_only:0, limit_in_pages:1, seg_not_present:0, useable:1}) = 0
mprotect(0xb76f4000, 8192, PROT_READ)   = 0
mprotect(0xb7738000, 4096, PROT_READ)   = 0
munmap(0xb76fa000, 111260)              = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
+++ killed by SIGSEGV +++
Ошибка сегментирования
ничего не понимаю :)

Deleted

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

stopitplease, Eddy_Em, ziemin, quest, emulek

Чуваки, вы столько друг другу подоказывали, в том числе и мне, какое я нубло, но так никто и не сказал. Друзья, какая разница? В паскале один код работает, в сишке отказался работать. Оказалось, что разное поведение. В чём разница поведения?

Понимаю что прошу разжевать и в рот положить. Уж звиняйте что нет желания и сил читать книги по Си для Си, наглая моя харя. Узнать хотел бы, буду рад если для кого-то не принципиальна моя лень и глупость :)

Ну позяяяяязяя!!!

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

Для простоты считай,что в паскале все массивы как static в C.

По крайней мере те, что в основном блоке.

Попробуй в своём паскале функцию с таким массивом замутить.

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

По-моему, уже сто раз сказали, что в C локальные объекты функции аллоцируются, в основном, на стеке. А в Паскале это, вероятно, статические данные

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

Короче, большие данные лучше аллоцировать с помощью malloc, а освобождать с помощью free. Или, как посоветовали выше, написать перед этим массивом «static».

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

Для простоты считай,что в паскале все массивы как static в C.

ок. а static размещает данные не в стек, а куда?

Попробуй в своём паскале функцию с таким массивом замутить.

попробовал, segfault) Классно, а как в паскале сделать чтоб работало? Ключевого слова нету. Интересно, значит данные что в функции помещаются в стек? :)

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

Короче, большие данные лучше аллоцировать с помощью malloc, а освобождать с помощью free

это как понял динамическая память? Это решение для больших данных внутри функций?

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

Я сказал тебе, как сделать. Что-то там проверять в уже откомпилированном коде - это бред

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

Оказалось, что разное поведение. В чём разница поведения?

Есть память на стеке (локальные переменные как у тебя) и есть память в куче (malloc, new).

malloc и new можно контролировать внутри программы, память на стеке нет и это вызывает неопределенное поведение.

я же за то чтобы была опция которая в режиме отладки (пусть и ценой большой потери производительности) поможет отследить это.

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

Это решение для больших данных внутри функций?

Да. И кроме того, пока не сделаешь free, данные никуда не уйдут, т.е. ты можешь передать их куда либо или вернуть из функции

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

ок. а static размещает данные не в стек, а куда?

Отдельная область. Причём она считается на этапе компиляции, так что переполнена быть не может.

попробовал, segfault)

Собственно тогда понятно твоё недоумение в топике. В паскале основной блок это основной блок. В C такого нет и main такая же функция, как и все остальные.

Классно, а как в паскале сделать чтоб работало? Ключевого слова нету.

Заводи глобально. Или через динамическую память.

Интересно, значит данные что в функции помещаются в стек? :)

Да, аргументы и локальные переменные. Кроме тех, под которые ты выделишь память сам. Поэтому не рекомендуется передавать в аргументах функции массивы в языках, которые это позволяют и всякого рода структуры.

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

В C такого нет и main такая же функция, как и все остальные.

Хотя, если уж копать... Основной блок в C есть. И он как раз включает в себя main.

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

И что? «Это» место не становится от этого блоком

Отчего же? Файлы состоят из блоков.

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

Спасибо тебе, и остальным. Вдуплил. Как понял паскаль требует строгой последовательности объявления, а Си позволяет декларировать в разных местах программы. Если не трудно, скажи про extern.

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

а Си позволяет декларировать в разных местах программы ключевым словом static.

fix. еще говорят что паскаль многословный :) еще б понять о extern, register и auto. ))

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

Если не трудно, скажи про extern.

Ну если формальное описание тебя не устраивает...

Будем говорить о функциях, как о самом сложном случае. Для лучшего понимания нужно думать как компилятор.

Что для него функция? Имя + Аргументы + Тело. Причём тело необходимо на этапах линковки и исполнения. Для проверки синтаксиса и генерации вызова компилятору необходимо и достаточно имени и аргументов, а тело нафиг не нужно.

Соответственно extern задаёт имя и (в большинстве случаев) аргументы.

Именно поэтому ошибки отсутствующих функций выдаёт линкер: компилятор даже не проверяет есть ли такая функция на самом деле или нет! Ему хватает имени.

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

Как понял паскаль требует строгой последовательности объявления, а Си позволяет декларировать в разных местах программы.

И,кстати, ты не совсем правильно понял. Суть в том, что в паскале основной блок выделен, а в C нет.

И там и там функции крашатся из-за переполнения стека.

И там и там глобальные переменные статические.

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

malloc и new

понял про стек, статическую и динамическую память. malloc и new для выделения динамической памяти? Почему два ключевых слова? у них тоже разное поведение? быстрый гугл сказал что new - c++, malloc - c. это так?

P.S. если не трудно, помоги с extern, auto, register. с любым из этих. лучше одним, что лучше дойдёт до меня :) Хочу понять в чём их смысл, и эквивалент паскаля.

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

Да. Только имя остаётся локальным, так что можешь во всех своих функциях завести переменную "a" и они будут разными и конфликтовать не будут.

Я как-то интересовался - им генерится какое-то псевдослучайное имя.

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

Ну если формальное описание тебя не устраивает...

я не совсем это понимаю)) глобальные переменные и функции я например в паскале объявляю в модуле:

unit
    exunit;

interface
    var
        unitx : integer = 1337;
        unity : real;

    procedure helloworld;

implementation

    procedure helloworld;
    begin
        writeln('Hello world');
    end;

end.
потом импортирую в нужный блок.
program ex1;
uses
    exunit;
var
    unitx : integer = 4000;
    unity : real = 1.0;

procedure helloworld;
begin
    writeln('die world');
end;

procedure myproc;
var
    unitx : integer = 22;
begin
    writeln('0: ', unitx);        // 22
    writeln('1: ', ex1.unitx);    // 4000
    writeln('2: ', exunit.unitx); // 1337
end;

begin
    writeln(exunit.unitx); // 1337
    writeln(unity);        // 1.0
    helloworld;            // die world
    exunit.helloworld;     // hello world
    myproc;
end.
по какой аналогии мне понять extern? как его вообще использовать? :)

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

static в отличие от объявления переменной за main определяет её область видимости только в main? а как в другой функции использовать эту статическую переменную?

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

В паскале все переменные и процедуры в блоке interface являются как extern в C, только аргументы указывать обязательно.

И кстати это не глобальные, а экспортируемые. ЕМНИП перекрывать их можно.

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

как сделать на Си, аналогично тому, что было в паскале? Друг, помоги если можешь. Библиотек немало, хочу знать как переписать.

Deleted
()
Ответ на: комментарий от Deleted
  • Юниты делишь на две части.
    • Всё, что в interface пихаешь в .h с префиксом extern;
    • Всё, что в implementation пихаешь в .c;
  • Соответственно, вместо uses делаешь #include<.h>
  • Т.к. блоков инициализации модулей в C нет, превращаешь их в функцию типа ${NAME}_init(). И обязательно вызываешь её перед использованием любых компонентов бывшего паскалевского модуля.
  • Все типы, естественно, приводишь;
  • ...

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

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

Кстате! Если у тебя реально библиотеки, то проще их компильнуть и использовать в C! Прям как библиотеки (.so).

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

хух, понял. а зачем такое может понадобиться? ведь всёравно генерится псевдослучайное имя за пределами функции main, которую к тому же нельзя использовать в других функциях. Почему сразу не объявлять за main'ом? а если не хочешь использовать в функции эту переменную - не используй. Зачем потребовался static?

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

Что-то я всё про C, да про C... А речь то о плюсах!

Сделай из этих своих модулей объекты! Инициализацию запихни в конструктор. Подпрограммы это методы. Переменные это члены класса. Которые в interface, те в public. которые в implementation те в private.

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

Зачем потребовался static?

Чтобы реализовать модель «переменную видно только в блоке объявления и вложенных». Псевдоимена выглядят как «__sdjfgjs?sdfsdfjhg#12521376» и их ты никак не используешь напрямую.

а если не хочешь использовать в функции эту переменную - не используй

Эта модель строгая. Вольностей программисту не положено.

В смысле выбора тебе никто не даёт.

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

На самом деле паскаль делает похоже. Не считая того, что аналога static я там не припомню.

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

ничего не понял. сделал три файлика: myunit.h

extern int    unitx = 1337;
extern double unity;
myunit.c
helloworld() {
    puts("Hello world");
}
ex1.c
#include <stdio.h>
#include "myunit.h"

main() {
    int unitx = 4000;
    printf("%d\n", unitx);
    helloworld();
}
а как работать с другой unitx? с той что 1337?

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

Что-то я всё про C, да про C... А речь то о плюсах!

не-не! :-D я использовал тег сpp потому что литеру «с» нельзя использовать в качестве тега.

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

а заодно как helloworld сделать в файле свою, и потом использовать то импортированную функцию, то локальную.

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

понял про стек, статическую и динамическую память. malloc и new для выделения динамической памяти? Почему два ключевых слова? у них тоже разное поведение? быстрый гугл сказал что new - c++, malloc - c. это так?

malloc просто выделяет блок
new выделяет блок, если не получилось - кидает исключение (которое можно выключить), если получилось - вызывает конструктор или множество конструкторов.

malloc/free - C, C++ new/new[]/delete/delete[] - C++

P.S. если не трудно, помоги с extern, auto, register. с любым из этих. лучше одним, что лучше дойдёт до меня :) Хочу понять в чём их смысл, и эквивалент паскаля.

extern ключевое слово используемое в хедере чтобы объяснить компилятору что пусть сейчас переменной/функции еще и нету, но на этапе линковки оно появится

auto устаревший модификатор появившийся опять в последнем стандарте C++ - для тех кому лень писать нормальные итераторы при проходе по контейнерам

register так же как inline - устаревшие модификаторы подсказывающие компилятору как оптимизировать

не помню точно, но возможно register важен при использовании asm внутри исходника.

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

у меня исходники на паскале, и в разных реализациях паскаля компилируются юниты то tpu, то ppu, то еще какие-то, хотя я использую только две версии компилятора (borland, freepascal).

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

Пойми: язык С является языком высокого уровня, но и порог вхождения там высок! Ты не можешь просто взять и понадеяться на менеджер памяти С, потому что его там нет! Ты сам обязан выделить нужное количество памяти при помощи alloc и удалить потом ненужное при помощи free. И это хорошо, ибо можно писать очень хорошие программы, которые не текут, не жрут бешеное количество памяти и работают быстро. На жабке-пхытоне-сидиезе и прочем говне так не сделать.

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

а как работать с другой unitx? с той что 1337?

Очевидно #include «myunit.h»

Кстати! У #include аргументы различаются. Если в кавычках, то он ищет от текущего каталога. Если в <> он ищет в системных.

А так - тупо меняй uses на #include "".

И ещё один момент. Паскаль это делает автоматом, а C нет: оформляй .h файлы вот так:

#ifndef _H_$NAME
#define _H_$NAME
... Здесь код
#endif

Вместо имени подставляй имя файла без расширения. Это предотвратит повторуню загрузку.

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

Пойми: язык С является языком высокого уровня, но и порог вхождения там высок! Ты не можешь просто взять и понадеяться на менеджер памяти С, потому что его там нет! Ты сам обязан выделить нужное количество памяти при помощи alloc и удалить потом ненужное при помощи free. И это хорошо, ибо можно писать очень хорошие программы, которые не текут, не жрут бешеное количество памяти и работают быстро. На жабке-пхытоне-сидиезе и прочем говне так не сделать.

Прям готовая паста :)

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

Очевидно #include «myunit.h»

я так и сделал: #include «myunit.h». и загрузил за main'ом переменную unitx с значением 1337. А потом в main'e определил переменную unitx с значением 4000. Как в main'e использовать переменную unitx с значением 1337?

#ifndef _H_$NAME
#define _H_$NAME
... Здесь код
#endif

А что это и зачем? какую повторную загрузку? погоди. давай вначале с областью видимости подключаемых переменных. Как использовать в одном блоке импортированную переменную и локальную с одним именем?

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

Тебе надо сделать так.

myunit.h

#ifndef _H_$MYUNIT
#define _H_$MYUNIT
extern int    unitx = 1337;
extern double unity;

void helloworld() //В загаловоных файлах надо обьявлять прототипы функций
#endif

myunith.c

void helloworld()
{
    puts("Hello world");
}

ex1.c

#include <stdio.h>
#include "myunit.h"

main()
{
    printf("%d\n", unitx);
    helloworld();
}

программа выведет:

1337
Hello World

Использовать одинаковые имена нелья.

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

А что это и зачем? какую повторную загрузку? погоди. давай вначале с областью видимости подключаемых переменных. Как использовать в одном блоке импортированную переменную и локальную с одним именем?

Давай рассмотрим всё с точки зрения компилятора/линкера/загрузчика.

Алгоритм приблизительно такой (в общих чертах):

  • компилятор
    • Читает исходники. Строит AST. Выявляет простейшие ошибки...
    • Как я уже говорил, тело его не интересуте до тех пор, пока он на него не напорется в процессе обработки файлов.
    • А в процессе обработки он создаёт объектные файлы. Кстати в порядке их следования в командной строке.
    • Второго прохода он не делает, так что на сцену выходит...
  • линкер
    • На предыдущем этапе созданы объектные файлы. Здесь начиняется увязка. Если ты где-то написал extern, то линкеру об этом осталась запись.
    • Теоретически он должен сразу же найти, но есть порядок. Порядок указывается опять-таки аргументами командной строки.
ziemin ★★
()
Ответ на: комментарий от nickionn

спасибо. очень доходчиво написано. сделал так: myunit.h

#ifndef H_MYUNIT
#define H_MYUNIT

extern int    unitx = 1337;
extern double unity;

#endif
#include "myunit.h"
helloworld() {
    puts("Hello world");
}
#include <stdio.h>
#include "myunit.h"

main() {
    int unitx = 0;
    printf("%d\n", unitx);
    helloworld();
}
и компилируя gcc ex1.c myunit.c получается ошибка:
myunit.h:4:15: предупреждение: «unitx» initialized and declared «extern» [по умолчанию включена]
In file included from myunit.c:1:0:
myunit.h:4:15: предупреждение: «unitx» initialized and declared «extern» [по умолчанию включена]
/tmp/ccrPX4rI.o:(.data+0x0): multiple definition of `unitx'
/tmp/ccatgGv9.o:(.data+0x0): first defined here

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

Не надо в .h определять функции. Вот ещё отличие C от паскаля: паскаль бьёт по рукам, а C рассчитывает, что ты знаешь, что делаешь.

В терминах паскаля ты попытался разместить в interface функцию.

Кстате. Ошибку выдал именно линкер! Буду надеятся, что на таких простых примерах ты поймёшь метод компиляции.

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

multiple definition of `unitx'

Ты 2 раза обьявляешь unitx, 1 раз в myuint.h второй раз в main(). Используй другое имя.

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

Спасиииибо! Работает! А что возвращает void? и почему нельзя использовать одинаковые имена? Ведь есть области видимости в функциях же!

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

А что возвращает void

Ничего.

и почему нельзя использовать одинаковые имена? Ведь есть области видимости в функциях же!

Потому что unitx глобальная переменная.

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

я не могу создать файлик myunit2.c в котором определю функцию пользуясь определениями из myunit.h и при этом, использовать эту функцию в ex1.c?

чтоб потом gcc ex1.c myunit.c myunit2.c? попробовал сейчас - не получается. пишет:

alex@localhost $ gcc ex1.c myunit.c muynit2.c 
In file included from ex1.c:2:0:
myunit.h:4:15: предупреждение: «unitx» initialized and declared «extern» [по умолчанию включена]
myunit.h:7:1: предупреждение: data definition has no type or storage class [по умолчанию включена]
In file included from muynit2.c:1:0:
myunit.h:4:15: предупреждение: «unitx» initialized and declared «extern» [по умолчанию включена]
myunit.h:7:1: предупреждение: data definition has no type or storage class [по умолчанию включена]
muynit2.c: В функции «helloworld2»:
muynit2.c:4:5: предупреждение: несовместимая неявная декларация внутренней функции «printf» [по умолчанию включена]
/tmp/ccO059lZ.o:(.data+0x0): multiple definition of `unitx'
/tmp/ccsWP4nY.o:(.data+0x0): first defined here
/tmp/ccO059lZ.o: In function `helloworld2':
muynit2.c:(.text+0x7): undefined reference to `unity'
muynit2.c:(.text+0xd): undefined reference to `unity'
collect2: ошибка: выполнение ld завершилось с кодом возврата 1

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

Потому что unitx глобальная переменная.

непонял. это когда я импортировал директивой #include да она стала глобальной (за функцией main)? а в main нельзя адресоваться к этой глобальной переменной имея локальную с таким же именем?

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

Ты опять 2 раза определяешь unitx, в этот раз уже в myunit2.c. Для myunit2.c тоже нужно создать заголовочный файл.

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

я почти, почти. помоги еще с myunit2.c{h} которая б использовала myunit.c{h} и использовалась в ex1.c и я совсем уж тогда :)

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

Научись отличать предупреждения от ошибок.

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

myunit.h

#ifndef H_MYUNIT
#define H_MYUNIT

extern const int unitx;
extern const int unity;

#endif

myunit.c

#include "myunit.h"

const int unitx = 1337;
const int unity = 4000;

myunit2.h

#ifndef H_MYUNIT2
#define H_MYUNIT2

void foo();

#endif

myunit2.c

#include "myunit2.h"
#include "myunit.h"

void foo()
{
    printf("%i/n",unitx);
    printf("%i/n",unity);
}

ex1.c

#include "myunit2.h"

int main()
{
foo()
}
nickionn ★☆
()
Ответ на: комментарий от nickionn

АаааааАааа! понял! Спасибо тебе, и ziemin. Благодаря вам. Из этого непонятно только зачем void, если функцию можно объявлять без возвращаемого значения.

P.S. const означает константу, да? неизменяемое значение?

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

пожалуйста, друг, только это осталось: зачем void, если функцию можно объявлять без возвращаемого значения? :)

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

АаааааАааа! понял!

Ничё ты не понял... Перевари.

Из этого непонятно только зачем void, если функцию можно объявлять без возвращаемого значения.

void значит ничего. Но это с одной стороны. С другой void это супертип, который включает в себя всЁ. Например: что такое 'c'? Это символ. Неважно в какой кодировке... Или (char (void *) &string)

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

Ничё ты не понял... Перевари.

я сделал так: определил в одном хедере переменные и функции (interface) и в c-файле их реализацию(implementation) (тонкость в том, что я определил содержимое этих переменных в interface - но в Си это работает, а в implementation - только функцию). В другом хедере я определил другую функцию(interface), в которой буду использовать переменные из первого хедера, а в втором c-файле подключил хедер этого файла и хедер содержащий объявления тех переменных которые я хочу использовать в этой функции. Затем в главной программе я подключил хедер системный, т.к. все они используют libc-функции, а затем второй хедер, так как он содержит объявления в том числе и первого хедера. Затем при компиляции передал в качестве аргументов компилятору главную программу (ex1.c) и вскомпилировал главный файл ex1 и второй с файл, а затем первый и второй файлы *.c содержащие реализацию хедеров (implementation).

Мне кажется понял, буду переваривать :)

void значит ничего

nil? NULL?

С другой void это супертип, который включает в себя всЁ. Например: что такое 'c'? Это символ. Неважно в какой кодировке... Или (char (void *) &string)

охохо, всё на сегодня видимо. я ничего не понял :)

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

Нельзя не указывать тип данных

Немедленно прекрати дезинформировать. void это без указания типа данных.

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

охохо, всё на сегодня видимо. я ничего не понял :)

Всё просто.Только не рассуждай с житейских понятий.

У компилятора машинное представление. Встань на его место, если хочешь понять.

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

охохо, всё на сегодня видимо. я ничего не понял :)

чувак тебе мозги пудрит и запутывает, он сам до конца не понимает что пытается объяснить. Лучше таки осиль прочитать какую-нибудь книжку по си.

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

int на самом деле..ещё честнее - нечто зависящее от соглашений по конкретной аппаратуре. Для x86, это то что поместилось хотя-бы в AX (регистр используемый для возврата значений).

void говорит компилятору что возвращаемое значение (AX или AX:DX и так далее) не имеет смысла и не может быть задействовано (хотя оно есть) ни в коде программы, ни при оптимизациях.

исторически: функция без указания типа (либо без прототипа) - int.

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

int на самом деле..ещё честнее

Такое ощущение, что ты продолжаешь разговор.

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

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

Сильно сказано. Аргументы будут?

Так не очиводно? Как начинаешь что-то объяснять, так сразу скатываешься в какой-то забористый бред. Вот сейчас, например, c void'ом фигню несёшь.

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

В чём разница поведения?

в сишке локальные переменные объявляются в стеке, ВСЕГДА.

В паскале ЕМНИП массивы объявляются в куче (т.е. через malloc(3)).

Подход сишки — скорость. Паскаля — надёжность. Но в сишке ты можешь и в куче выделить, и в стеке. А в паскале ты можешь только молится святому Вирту, что-бы компилятор догадался сделать то, что тебе нужно.

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

еще говорят что паскаль многословный

правильно говорят.

extern

из-за краткости синтаксиса компилятор не может отличить объявление от описания. Потом считает, что если ты пишешь в глобальной области

int x;

то ты объявляешь x (выделяешь для него 4 байта). А если ты хочешь просто описать x, который объявлен в другом месте, юзай extern

register

не нужная подсказка компилятору, что переменную _лучше_ хранить в регистре, а не в стеке. В 21ом веке таких тупых компиляторов не используется.

auto

вредное слово, которое НЕ НУЖНО использовать, ибо в C++ там совсем иной смысл.

значит оно «использовать стек», и работает по умолчанию. Для единообразия ввели, а потом было уже поздно что-то менять.

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

static в отличие от объявления переменной за main определяет её область видимости только в main?

да.

а как в другой функции использовать эту статическую переменную?

функция f() может отдать другой функции указатель на свою static int x;, и тогда другая f2() может юзать этот x.

А вот если просто int x, то отдать указатель нельзя, ибо x будет уничтожена.

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

тогда зачем void? ведь и объявление просто функции ничего не возвращает.

«просто» возвращает int.

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

void значит ничего

nil? NULL?

void значит НИЧЕГО

NULL это указатель, который НИКУДА не указывает.

nil, ЕМНИП это просто пустой объект. Хотя я не в курсе, что это.

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

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

ты чушь порешь.

void — просто функция, которая просто ничего не возвращает в рамках C/C++. Нет, в рамках машинного представления конечно остаётся какой-то мусор в регистрах, но он не имеет смысла.

Да, это важно при оптимизации, ибо функция может быть объявлена в другом модуле, и компилятор не увидит, нужно-ли кому-то возвращаемое значение, или нет. Ну и придётся что-то возвращать, и тратить время. Как например в printf(3), которая возвращает число напечатанных байт(а может символов, я не помню). Обычно эта информация не используется, но всё равно формируется и передаётся в коде.

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

детка, иди кури стандарт на предмет осознания того, что такое void, и что такое void*. Ты не поверишь, но это не просто разные вещи, это тёплое и мягкое.

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

в сишке локальные переменные объявляются в стеке, ВСЕГДА.
в сишке ты можешь и в куче выделить, и в стеке

так куда локальные переменные выделяются? через static выделяются в кучу, а без указания static просто выделяются в стек? malloc, как понял - динамическая память и является также кучей? но ведь делая static переменная в си, я не делаю malloc. Также как и в паскале, объявляя переменную я не делаю new/dispose. Но могу и new/dispose если хочется. В сишке как понял также.

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

функция f() может отдать другой функции указатель на свою static int x;, и тогда другая f2() может юзать этот x.

А вот если просто int x, то отдать указатель нельзя, ибо x будет уничтожена.

приведи пример, пожалуйста, самый простой, иллюстрирующий это.

«просто» возвращает int.

и int func - тоже возвращает int.

void значит НИЧЕГО
NULL это указатель, который НИКУДА не указывает.
nil, ЕМНИП это просто пустой объект. Хотя я не в курсе, что это.

это как NULL, если я правильно понял. nil - это ноль для указателя. Но ноль не как 0, а как отсутствие чего бы то не было.

Да, это важно при оптимизации, ибо функция может быть объявлена в другом модуле, и компилятор не увидит, нужно-ли кому-то возвращаемое значение, или нет. Ну и придётся что-то возвращать, и тратить время. Как например в printf(3), которая возвращает число напечатанных байт(а может символов, я не помню). Обычно эта информация не используется, но всё равно формируется и передаётся в коде.

Спасибо за разъяснение. Получается void для того, чтоб объявить процедуру вместо функции?

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

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

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

Подойди к вопросу со стороны «железа».

Рассмотрим процесс загрузки. Кстати тут очень важно понять, что программа не сама запускается, а её запускают!

То, как система шарит по диску, проверяет, что файл исполняемый, сверяет всякие контрольные суммы мы опустим.

Сначала в дело вступает загрузчик. Он парсит заголовок исполняемого файла (в случае очень древнего «прямого» формата coff создаёт). Оттуда он выясняет, из каких секций состоит программа. И резервирует под них память

Далее начинается встроенный загрузчик самой программы (это всё происходит ДО работы программы).

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

Секции бывают разные. В Фон-Неймовской архитектуры данные и код это одно и тоже. Проще говоря ячейке памяти всё равно, что в ней находится: код или просто число.

Но, для упрощения файл всё-таки делят на секции кода. Плюс в 86 (и других) процах можно установить у памяти признак исполняемости.

Но! Данные бывают разные. Например ты можешь замутить массив чисел в программе. Я имею в виду реально ввести в программу числа. Например:

const double data[] = { 3.14, 2.7, 1.6 ........};

Это инициализированные данные (уже подраздел данных).

А можешь замутить данные, которые «не требуют инициализации». Проще говоря есть соглашение, что по-умолчанию (это 0).

Таким образом возникает ещё одно деление. Отдельно идут неинициализированные данные, которые установишь ты. Компилятор не дурак и два раза работу делать не будет.

Теперь переходим к работе твоей программы. Код уже проинициализирован на нескольких уровнях (но и на разных сегмента). Однако для работы требуется стек.

Каждый раз, когда ты вызываешь в коде функцию, в стек запихивается адрес возврата. Кроме того на такой архитектуре туда же и пихаются локальные переменные (есть архитектуры с отдельным стеком данных).

Т.о. main это всего лишь обычная рядовая функция, которую вызывает настоящая запускаемая функция. Она находится вроде в библиотеке libstart или как-то так.

Тьфу-ты блин. Как-то размазанно получилось. Задавай свои ответы.

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

Зато из поисковиков кто-нить придёт. Кому-нибудь пригодится. А на меня стих нашёл :)

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

Кстати. Следует очень чётко разделять программную и аппаратную модели. Многое из того, что я описал, реализовано чипом.

Но в любом случае программная модель более полная. Просто потому, что эмулирует недостающие части оборудования.

Плюс я ещё не расписал инициализацию библиотек. Это отдельная песня. Нужно понимать, что загрузка производится загрузчиком ОС (хотя можно и грузить динамически), и у них есть собственные инициализаторы.

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

в сишке локальные переменные объявляются в стеке, ВСЕГДА. в сишке ты можешь и в куче выделить, и в стеке

так куда локальные переменные выделяются?

В СТЕК. Неграмотный что-ли? Куча в сишке глобальна, и единственна.

через static выделяются в кучу, а без указания static просто выделяются в стек?

нет. Через static выделяются компилятором во время компиляции, в специальной секции бинарника.

В куче в рантайме функцией malloc(3).

malloc, как понял - динамическая память и является также кучей?

в си — да. Хотя в теории можно и в стеке сделать динамическую. И ещё где-то. Зависит от твоей упоротости, и упоротости аффтора ЯП.

но ведь делая static переменная в си, я не делаю malloc.

верно. Если сделать static строку «мудак», её можно потом нагрепать в бинарнике.

Также как и в паскале, объявляя переменную я не делаю new/dispose. Но могу и new/dispose если хочется. В сишке как понял также.

я не знаю, как оно там сейчас реализовано в паскакале.

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

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

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

А ты не видишь, что ему больше на ЛОРе поболтать охота, а не узнавать что либо?

мне интересно и то и это.

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

Но в любом случае программная модель более полная. Просто потому, что эмулирует недостающие части оборудования.

какие например?

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

Например сопроцессор. В некоторых случаях прерывания.

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

приведи пример, пожалуйста, самый простой, иллюстрирующий это.

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

int *f1()
{
	static int a[9001];
	memset(a, 1, sizeof(int)*9001);
	return a;
}

int *f2()
{
	static int a[9001];
	memset(a, 2, sizeof(int)*9001);
	return a;
}

int main()
{
	int *a1 = f1();
	int *a2 = f2();
	printf("a1=%x, a2=%x\n", a1[17], a2[17]);
	return 0;
}

попробуй убрать static, и посмотри что получится.

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

В СТЕК. Неграмотный что-ли? Куча в сишке глобальна, и единственна.

просто я понял тебя так: что локальные переменные объявляются в стеке, но в отличие от паскаля, где есть только один вариант, в сишке можно объявлять их и в стеке, и в куче.

нет. Через static выделяются компилятором во время компиляции, в специальной секции бинарника.
В куче в рантайме функцией malloc(3).

так.

верно. Если сделать static строку «мудак», её можно потом нагрепать в бинарнике.

ага, а если я делаю «неинициализированную переменную», то она заполняется чем-то условным, а потом в коде, инструкцией помещается в неё что-то своё? переменная при этом остаётся в секции бинарника?

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

эти разделы по разному называются и находятся в зависимости от типа исполняемого файла, ОС и архитектуры?

Я тут распинаюсь, а ты главного так и не понял? Это модель по которой загружается любой процесс. Может я чего и упустил, но в общих чертах это так.

Рано тебе сосредотачиваться на деталях. Сначала пойми в общем.

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

и int func - тоже возвращает int.

ты нерусский что-ли? void НИЧЕГО НЕ ВОЗВРАЩАЕТ.

это как NULL, если я правильно понял.

я не знаю, и знать не желаю, что там у тебя nil значит.

Советую и тебе забыть.

Спасибо за разъяснение. Получается void для того, чтоб объявить процедуру вместо функции?

в сишке есть только функции, они же «процедуры». Функция может возвращать значение, а может и не возвращать. Зависит от её описания.

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

просто я понял тебя так: что локальные переменные объявляются в стеке, но в отличие от паскаля, где есть только один вариант, в сишке можно объявлять их и в стеке, и в куче.

ну так правильно, есть два варианта: в стеке и СТАТИЧЕСКИ. НЕ в куче!

В куче можно только через malloc(3), и всё.

ага, а если я делаю «неинициализированную переменную», то она заполняется чем-то условным, а потом в коде, инструкцией помещается в неё что-то своё? переменная при этом остаётся в секции бинарника?

не. Статическая неинициализированная рамером 11 байт заполняется нулями. А если ты её инициализировал «мудак», то заполняется байтами «мудак».

Потому строки всегда const. Ибо программы на сишке не могут менять свой код (только грязными хаками).

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

Потому строки всегда const.

Неправда. На Фон-Неймановской архитектуре добиться этого можно только извернувшись. На микроконтроллерах с Принстонской архитектурой не только строки, а вообще все переменные немодифицируемы.

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

Потому строки всегда const.

Неправда.

правда. Я про сишку говорил. А если ты про архитектуру, то в современных x86 уже много лет тоже так. Писать в код было возможно только в 80х годах прошлого века. Но видно 30+ лет прогресса прошли мимо тебя.

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

А если ты про архитектуру, то в современных x86 уже много лет тоже так

Какой же ты ограниченный. Написал же, что в принстонской архитектуре.

Но видно 30+ лет прогресса прошли мимо тебя.

Сам нагуглишь контроллер или мне? Их не меньше (а то и больше, чем ПК). А язык один - C.

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

Сам нагуглишь контроллер или мне?

в контроллере запись в код обычно просто бессмысленна, там же ROM(которая просто так, как RAM, не переписывается).

Не, ну может и есть какие-то чипы с RAM вместо ROM, но я не очень понимаю, на кой ляд они нужны.

Впрочем, я в этой вашей встройке не очень. Я уже много лет работаю исключительно с нормальными CPU.

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