|
|
  |
Вопросы по C от ламера, В книжках ответа чёта не нахожу |
|
|
|
Apr 15 2009, 04:41
|
Профессионал
    
Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757

|
Цитата(Скопидор @ Apr 15 2009, 02:13)  1.А обязательно ли в препроцессорной директиве #include использовать файлы с расширением .h ? Т.е. могу ли, например, написать файл с раширением .my и вложить его содержимое в основной файл с помощью директивы #include? Да. Расширение вообще ни причём. См. ниже. Цитата 3. Использование #include подразумевает экспортирование ресурсов из .h-файла. Ничего подобного. #include -- это просто включение текста одного файла в другой файл. Ничего больше. Почитайте про препроцессор. Цитата Ссылка битая. Сайт не грузится Ссылка не битая. А сайт действительно не грузится. С ним это бывает крайне редко. Попробуйте попозже. Это лучший ресурс в рунете по программированию.
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 07:30
|
Guests

|
Цитата(andrew_b @ Apr 15 2009, 08:41)  Ничего подобного. #include -- это просто включение текста одного файла в другой файл. Да я в курсе. Просто я говорил о том, что можно код распределить по файлам так, что не CPP-файл будет юзать ресурсы из H-файла, а наоборот. И это будет выглядеть как импортирование. Приведу пример CODE // Файл f.h int I,J; int F1(int, int); // Прототип функции, реализация которой будет определена в C-файле int F2(void); // Функция, которая использует F1 { return (F1(I,J)); }
// Файл main1.c #include "f.h " int Result; // -------------------- int F1( int A, B) { return (A*B) } // -------------------- void main (void) { I = 3; J = 4; Result = F2(); } // --------------------
// Файл main2.c #include "f.h " int Result; // -------------------- int F1( int A, B) { return (A+B) } // -------------------- void main (void) { I = 3; J = 4; Result = F2(); } // -------------------- Вот и получается, что алгоритм работы определённой в файле f.h функции F2 зависит от того, в какой файл будет вложен f.h: в main1.c или в main2.c. Т.е. всё выглядит так, что как будто бы в функцию F1 импортируется реализация из C-файла, т.к. результат, возвращаемый функцией F1 (а значит и использующей её F2) зависит от того, в какой файл был вложен f.h. Цитата(andrew_b @ Apr 15 2009, 08:41)  Да. Расширение вообще ни причём. См. ниже. А я вот когда работал в WinAVR, то там при создании проекта создаются категории Header и Source. И если включить файл *.h в категорию Header, то можно даже в исходнике не писать #include *.h. Так как компилятор сам поймёт что *.h файл нужно вложить во все исходники проекта (во все *.c файлы). Или я не прав? Вот я и думаю, что если у меня файл, включнённый в категорию Header будет иметь расширение не h, а другое? "Подцепит" ли его компилятор автоматом к проекту?
Причина редактирования: Уменьшение видимого размера цитаты исходника.
|
|
|
|
|
Apr 15 2009, 07:41
|

Беспросветный оптимист
     
Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646

|
Цитата(Скопидор @ Apr 15 2009, 11:30)  И если включить файл *.h в категорию Header, то можно даже в исходнике не писать #include *.h. Так как компилятор сам поймёт что *.h файл нужно вложить во все исходники проекта (во все *.c файлы). Хрень какую-то несёте в массы. Компилятор не может ничего никуда автоматом "подцеплять". Он может тупо компилить, что ему дадут. Максимум что может быть, так это что ваши h-файлы будут видны из любого места проекта, и можно будет инклудить их просто #include "some_header.h" без указания абсолютного пути. Опять же, к компилятору это никаким боком, это делает утилита, формирующая makefile.
Причина редактирования: Излишнее цитирование.
--------------------
Программирование делится на системное и бессистемное. ©Моё :) — а для кого-то БГ — это Bill Gilbert =)
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 07:47
|
Guests

|
Цитата(SysRq @ Apr 15 2009, 05:45)  Срочно читать как из .cpp получается .exe. В 2 этапа: сначала по отдельности компилируем все файлы (получаем OBJ-файлы), потом линкуем. Правильно? Цитата(SysRq @ Apr 15 2009, 05:45)  Вы какой язык изучать собрались? C++? Инкапсуляция, наследование, и т.п. -- туда читайте. Вопрос отпадет. О глобальных переменных флудить не будем, тема уже была, ищите на форуме. Т.е. если «очень постараться» (  ) (ну не внимательно подойти к выбору идентификаторов в своей программе), то всё же есть вероятность «наступить на грабли» и случайно экранировать идентификаторы из стандартной библиотеки в своей проге? Я не говорю сейчас о своих идентификаторах, начинающихся на _, __ или заканчивающихся на _t. Допустим, к примеру, я такой дуб, что не знал, что в библиотеке уже юзаются cin и cout. И взял, и переопределил их в своей проге. Может такое быть? Цитата(SysRq @ Apr 15 2009, 05:45)  За goto - секирбашка. Особенно в C++. Флудить не будем, тема уже была тоже. Да я не собираюсь флудить, нужен или не нужен goto. Просто хотел узнать как это реализуется: осуществляется «прыжок» за пределы блока и при этом, КАК-ТО, восстанавливается контекст, сохранённый на входе в блок. P.S. Прошу прощения, если мои вопросы кажутся глупыми, я ж говорю, я ламер.
|
|
|
|
|
Apr 15 2009, 07:54
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Скопидор @ Apr 15 2009, 10:44)  Допустим, к примеру, я такой дуб, ... Может такое быть? Запросто. Но достаточно либо определить свои cin/cout в своём пространстве имён oak и квалифицировать при использовании oak::cin либо не переносить сущности стандартной библиолтеки в глобальное пространство имён, что происходит при использовании Код #include <iostream.h> вместо Код #include <iostream> или при совсем глобальном переносе Код using namespace std; В этом случае к "стандартно-библиотечным" придётся обращаться как к std::cin, но они тоже не пересекутся с новоявленными. А вообще поломать можно что угодно.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 08:09
|
Guests

|
Цитата(MrYuran @ Apr 15 2009, 11:41)  Хрень какую-то несёте в массы. Ну когда мы делаем "add File to Project" мы же хидеры добваляем в категорию "Header". И после того как файл проекта (dsn по-моему) сформирован, компилятор знает, какие *.h файлы юзать при сборке. Разве не так? Цитата(MrYuran @ Apr 15 2009, 08:31)  C чего бы это вдруг?  Никому он ничего не должен. Блок {} означает всего лишь составной оператор, никаких переходов и контекстов не имеется в виду. А я прочитал в книшшке, что если внутри {…} определяются локальные переменные, то составной оператор автоматом становиться блоком со всеми вытекающими последствиями (сохранение контекста процессора при входе в блок, создание локальных переменных в стеке и т.п.) Цитата(ReAl @ Apr 15 2009, 11:54)  определить свои cin/cout в своём пространстве имён oak и квалифицировать при использовании oak::cin А что такое «oak»? …. Т.е. Ваше сообщение было к тому, что «сломать» очень сложно? Но ведь стандартная библиотека – это не только классы и шаблоны.
Причина редактирования: Излишнее цитирование.
|
|
|
|
|
Apr 15 2009, 08:19
|
Профессионал
    
Группа: Свой
Сообщений: 1 975
Регистрация: 30-12-04
Из: Воронеж
Пользователь №: 1 757

|
Цитата(ReAl @ Apr 15 2009, 11:54)  Так это давным-давно deprecated. Цитата(Скопидор @ Apr 15 2009, 12:09)  Ну когда мы делаем "add File to Project" Ну и при чём тут компилятор. Цитата мы же хидеры добваляем в категорию "Header". И после того как файл проекта (dsn по-моему) сформирован, компилятор знает, какие *.h файлы юзать при сборке. Разве не так? Компилятор про проект ничего не знает.
|
|
|
|
|
Apr 15 2009, 08:30
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Скопидор @ Apr 15 2009, 10:47)  Да я не собираюсь флудить, нужен или не нужен goto. Просто хотел узнать как это реализуется: осуществляется «прыжок» за пределы блока и при этом, КАК-ТО, восстанавливается контекст, сохранённый на входе в блок. Обычно ничего никуда не сохраняется и не восстанавливается в таких блоках. Код voif foo() { int i = 0; { char c; ... } ++i; { long l; ... } --i; } Компилятор анализирует всю функцию и в исполняемом коде уже на входе в функцию на стеке резервируется, грубо говоря Код struct { int i; union { char c; long l; }; } local_variables; и больше стек туда-сюда не дёргается, просто происходит использование места на стеке в соответствии с деревом вложенных блоков кода. При минимальной современной оптимизации ещё и происходит анализ использования переменных и если какая-то используется до середины и дальше не нужна, а какая-то другая наоброт - используется только от середины (первое использование после последнего использования той), то они тоже накладываются в стеке для экономии его размера. При этом переход по goto ничего не ломает (если он не обходит инициализацию переменной при попадании на метку, т.е. вопросы не к точке прыжка goto, а к точке приземления), так как структура/объединение на стеке остаются неподвижными, меняется только интерпретация. Естественно, это так просто только для типов без конструкторов/деструкторов. Особенно учитывая то, что во вложенных вызовах могут произойти исключения, которые подействуют "аналогично goto" с точки зрения этих объектов, а при отсутствии в данной функции try/catch её вообще всё "прошьёт". Поэтому для них в стековых кадрах функций устраиваются записи о деструкторах, которые необходимо выполнить при выходе из блока и порядке этих вызовов, при выходе из любого блока по goto/return/исключению просматриваются эти записи и вызываются необходимые деструкторы для автоматических объектов в блоках (unwind). Код #include <iostream>
class FOO { public: FOO(int i_) : i(i_) { std::cout << __PRETTY_FUNCTION__ << " (" << i << ")\n"; } ~FOO() { std::cout << __PRETTY_FUNCTION__ << " (" << i << ")\n"; } private: int i; };
int main(int ac, char **av) { FOO f1(1); { FOO f2(2); if(ac == 1) goto aaa; // в случае перехода даже не сконструируется, но место на стеке под поле i зарезервировано заранее FOO f3(3); } aaa:; } Вызываем с аргументом в командной строке (goto не выполняется) Цитата FOO::FOO(int) (1) FOO::FOO(int) (2) FOO::FOO(int) (3) FOO::~FOO() (3) FOO::~FOO() (2) FOO::~FOO() (1) Вызываем без аргумента Цитата FOO::FOO(int) (1) FOO::FOO(int) (2) FOO::~FOO() (2) FOO::~FOO() (1) Цитата(Скопидор @ Apr 15 2009, 11:09)  А что такое «oak»? http://www.abbyyonline.ru/Translate.aspx?l...1&words=oakМожете для своих вещей выбрать другое имя. Можете несколько, для разных частей проекта свои. Цитата(Скопидор @ Apr 15 2009, 11:09)  Т.е. Ваше сообщение было к тому, что «сломать» очень сложно? Но ведь стандартная библиотека – это не только классы и шаблоны. Оно к тому, что в языке есть средства для того, чтобы можно было не ломать. Цитата(andrew_b @ Apr 15 2009, 11:19)  Так это давным-давно deprecated. У меня просто до сих пор в ходу mingw32-gcc 3.4.2 пятилетней давности, у него в backward/ ещё болтается всё
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 08:39
|
Guests

|
Цитата(andrew_b @ Apr 15 2009, 12:19)  Ну и при чём тут компилятор. Компилятор про проект ничего не знает. А для кого тогда создаётся DSN-файл? ..................................... ..................................... ..................................... ReAl!! Спасибо за столь развёрнутый и подробный ответ. Я его весь пока не асисилил, но работаю над этим  Т.е. как я понял, компилятор выделяет память под все локальные переменные любого уровня вложенности блоков на входе в функцию? Т.е. если в функции описана переменная i, а во вложенном в функцию блоке – переменная j, то память в стеке и под i и под j будет выделена на входе в функцию, а уничтожена на выходе по команде return?
Сообщение отредактировал Скопидор - Apr 15 2009, 08:42
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 10:09
|
Guests

|
Цитата(andrew_b @ Apr 15 2009, 13:11)  Видимо, для IDE. IDE != компилятор. Но ведь эта IDE позволяет не писать в каждом файле #include ..., т.е. берёт на себя функции компилятора?
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 15:42
|
Guests

|
Вопрос №7.
Можно ли использовать при объявлении (описании или определении) переменной использовать идентификатор типа, который будет опредёлён ниже или в другом файле? И как это сделать?
============================ Вопрос №8.
Вопрос по typedef.
Зачем писать так: typedef unsigned int UINT Если можно так: #define UINT (unsigned int)
В чём принципиальная разница?
================================== Вопрос №9.
Можно ли в C++ заставить компилятор АВТОМАТИЧЕСКИ генерировать код, контролирующий выход результатов вычислений за пределы допустимого диапазона? Есть ли для этого какие-то специальные ключи компиляции?
Допустим, есть такой фрагмент кода:
unsigned short int i , j , k ; … k = i + j // что будет если (i+j) > 65535?
============================ Вопрос №10.
Для чего нужно ключевое слово «signed» если оно никогда на практике не используется?
============================== Вопрос №11.
Зачем нужны две формы инициализации переменной?
int i = 10 и int i(10)
В чём между ними принципиальная разница?
Сообщение отредактировал Скопидор - Apr 15 2009, 15:44
|
|
|
|
|
Apr 15 2009, 20:00
|

Чайник, 1 литр
   
Группа: Свой
Сообщений: 655
Регистрация: 17-05-06
Из: Moscow
Пользователь №: 17 168

|
Цитата(Скопидор @ Apr 15 2009, 19:42)  ...идентификатор типа, который будет опредёлён ниже или в другом файле? Тип должен быть известен (прототип, или еще как-либо; declaration). Известным тип так же считается, если вы как раз его и описываете (простейший пример - свзяный список структур: в структуре при ее обявлении есть указатель на неё же). Цитата(Скопидор @ Apr 15 2009, 19:42)  Зачем писать так: typedef unsigned int UINT Код #define int_pointer int * int_pointer myint1, myint2; После подстановки препроцессором: Код int *myint1, myint2; // первое - указатель, а второе-то вовсе нет; а с typedef все будет правильно Цитата(Скопидор @ Apr 15 2009, 19:42)  ...АВТОМАТИЧЕСКИ генерировать код, контролирующий выход результатов вычислений за пределы допустимого диапазона? k = i + j // что будет если (i+j) > 65535? Хороший компилятор выдаст предупреждение о возможном переполнении. Будет отброшено то что не влезает, старшие биты. Цитата(Скопидор @ Apr 15 2009, 19:42)  Для чего нужно ключевое слово «signed» если оно никогда на практике не используется? По-умолчанию char в WinAVR (и не только) считается unsigned (опция компилятора). Использовать signed - единственный способ заставить его в таком случае работать как со знаковой. Цитата(Скопидор @ Apr 15 2009, 19:42)  int i = 10 и int i(10) Присваивание значения либо через оператор =, или через конструктор.
|
|
|
|
Guest_Скопидор_*
|
Apr 15 2009, 20:34
|
Guests

|
Цитата(SysRq @ Apr 16 2009, 00:00)  Присваивание значения либо через оператор =, или через конструктор. А когда лучше какую из форм юзать? P.S. И ещё. Насколько я понял форму инициализации со скобками можно юзать только для локальных переменных. Почему?
Причина редактирования: Нарушение п.3.4 Правил форума.
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|