Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Структуры и указатели на них! Вложенные... 
:(
    Опции темы
Profi80
Дата 6.8.2005, 04:12 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Уважаемые коллеги, прошу вас помочь с разбором кода open source трекера (программы для написания музыки). Главным образом, мои вопросы касаются работы со структурами. Я уже несколько дней пытаюсь понять алгоритм работы одного участка кода, но пока безуспешно. Надеюсь среди вас найдутся спецы, для которых решение этой задачки не составит большого труда. Вот код:

Файл a.cpp содержит инициализацию структуры
extern sound_struct xm; для глобального использования (структура содержит информацию о музыкальном треке).

объявление структур sound_struct и module в файле b.h:
Код

struct sound_struct
{
    module     *song;
    channel    *channels[MAX_CHANNELS];

    long       status;           
    long       need_to_stop;     
    long       stream_stoped;   
    long       song_finished;    
    long       freq;             
    ulong      *linear_tab;      
    uint16     *stereo_tab;      
    uchar      *vibrato_tab;     
    long       chans;            
    long       sample_int;       
    long       freq_int;        
    long       global_volume;
}

struct module
{
    uchar   id_text[17];
        uchar   name[20];
    uchar   reserved1;
    uchar   tracker_name[20];
    uint16  version;
    ulong   header_size;
    uint16  length;
    uint16  restart_position;
    uint16  channels;
    uint16  patterns_num;
    uint16  instruments_num;
    uint16  freq_table;
    uint16  tempo;
    uint16  bpm;
    uchar   patterntable[256];
    
    pattern    *patterns[256];
    instrument *instruments[128];
};

Процесс загрузки трекерного модуля начинается с файла c.cpp, который содержит следующую функцию:
load_module( name, &xm ); //загружаем музыкальный модуль

определение функции в файле d.cpp :
Код

void load_module( char *filename, sound_struct *xm )
{
     //Load XM:
    xm_load( f, xm );
    
}

переходим в функцию xm_load( f, xm ), её определение в файле e.cpp:
Код

int xm_load( FILE *f, sound_struct *xm )
{
    module *song = (module*) xm->song; //main song
    char *sptr = (char*)song;
    fread(sptr,332,1,f); //load header
    song->id_text[0] = 'E'; song->id_text[1] = 'x'; song->id_text[2] = 't'; song->id_text[3] = 'e';

.........
}


*пояснение: fread(sptr+4,332,1,f) - функция перемещает 322 байта из файла с дескриптором f в *sprt

ВНИМАНИЕ! ВОПРОСЫ:
1. Можно ли таким образом:
char *sptr = (char*)song;
fread(sptr,332,1,f); //load header
проинициализировать структуру module* song; в структуре sound_struct xm; (скопировать данные из файла по адрусу указателя). Дебаггер говорит, что нельзя :-), тогда зачем это здесь?

2. Почему не удаётся записать данные в id_text[] таким образом:
song->id_text[0] = 'E'; song->id_text[1] = 'x'; song->id_text[2] = 't'; song->id_text[3] = 'e'; ?

3. Обязательно ли инициализировать структуру, чтобы давать указатель на неё? Структура sound_struct содержит указатель на структуру module* song;
При обращении к её элементам (song->id_text[0] = 'E';) куда записываются данные- в sound_struct или куда-то в другое место?

Заранее спасибо!
  Вверх
LPBOY
Дата 6.8.2005, 10:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 228
Регистрация: 12.7.2005

Репутация: 20
Всего: 20



Цитата

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

Я не спец, но попробую высказать свое мнение... (оно может быть и субъективным, конечно).

Цитата

1. Можно ли таким образом:
char *sptr = (char*)song;
fread(sptr,332,1,f); //load header
проинициализировать структуру module* song; в структуре sound_struct xm; (скопировать данные из файла по адрусу указателя).
Дебаггер говорит, что нельзя :-), тогда зачем это здесь?

Думаю можно. Но инициализация происходит "насильственным" способом, через опасные приведения типов
и прямую запись по адресу памяти.
Хотя для С обычный прием - полагаться на внутренне представление данных, (а в С++ это скорее хак),
ведь С - язык системного программирования.
Неудивительно, что это не нравится деббагеру (компилятор наверно С++, а не С?), хотя фактически ошибки нет, ИМХО.

Цитата

2. Почему не удаётся записать данные в id_text[] таким образом:
song->id_text[0] = 'E'; song->id_text[1] = 'x'; song->id_text[2] = 't'; song->id_text[3] = 'e'; ?

Почему не удается? Что говорит компилятор\деббагер?
Цитата

3. Обязательно ли инициализировать структуру, чтобы давать указатель на неё?
Структура sound_struct содержит указатель на структуру module* song;

В принципе достаточно чтобы указатель указывал на существующую структуру пусть и не инициализированную.
Но опять-таки деббагер С++ может ругаться.

Цитата

При обращении к её элементам (song->id_text[0] = 'E';) куда записываются данные- в sound_struct или куда-то в другое место?

Фактически они записываются в структуру module, которая является полем структуры sound_struct.

P.S. Интересно узнать название твоего компилятора.

Это сообщение отредактировал(а) LPBOY - 6.8.2005, 12:43
--------------------
Каждый человек по-своему прав, а по-моему нет...
PM MAIL   Вверх
Profi80
Дата 7.8.2005, 01:34 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











To LPBOY: Спасибо, что откликнулся и попытался помочь. Я пишу в Codewarrior, компилятор C++.

На самом деле причина ошибок была вот в чём - т.к. в sound_struct был задан указатель module* song; и нигде не была инициализирована переменная типа module, указатель естественно указывал на ноль! И потому как это структура, а не char или int, данные уходили в никуда

Решение заключается в том, чтобы указатель получил какой-то реальный адрес, а именно вот так: module* song[1];
после этого можно обращаться к полям структуры module в структуре sound_struct.

Как всегда, разобраться помог дебаггер + крепкий кофе на ночь smile

Но, так и не понял, почему автор исходников написал именно так, как было? И как оно всё работало? Видимо, на С такое допускается...
(кстати, код написан по уверениям автора под gcc, но судя по манере исполнения это больше похоже на C, чем на C++)

  Вверх
LPBOY
Дата 7.8.2005, 02:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 228
Регистрация: 12.7.2005

Репутация: 20
Всего: 20



Ты меня не понял.
Цитата

На самом деле причина ошибок была вот в чём - т.к. в sound_struct был задан указатель module* song; и нигде не была инициализирована переменная типа module, указатель естественно указывал на ноль!

Подожди... Если указатель указывал на ноль, это не значит, что "нигде не была инициализирована переменная типа module", а значит что ее и вовсе нету. Если же она есть (т.е. где-то была создана и ее адрес присвоен указателю song), но просто не инициализирована, то тут все в порядке!

Цитата

И потому как это структура, а не char или int, данные уходили в никуда

Опять не согласен. В книжках по системному программированию я очень часто встречал такой приём. Так делают, чтобы не заморачиваться с присваиванием каждому полю структуры, а заполнить ее одним махом, заранее подготовленной побайтовой копией инициализированной структуры из файла. Данные не уходили "вникуда", т.к. адрес-то не менялся, происходило лишь преобразование типа указателя (char*)song в char*, т.е. структура рассматривалась как последовательность байтов.
Тут происходит следующее:
module *song = (module*) xm->song;
char *sptr = (char*)song;//Структура module трактуется как последовательность однобайтных символов.
fread(sptr+4,332,1,f); //Затем она заполняется (инициализируется) "одним махом" из файла.
Первые 4 байта не инициализируются как видишь, - они инициализируются "обычным" способом:
Цитата

song->id_text[0] = 'E';
song->id_text[1] = 'x';
song->id_text[2] = 't';
song->id_text[3] = 'e';

Cтруктура module может быть не инициализирована, но ОНА ОБЯЗАТЕЛЬНО ДОЛЖНА БЫТЬ СОЗДАНА, И ЕЕ АДРЕС ДОЛЖЕН БЫТЬ ПРИСВОЕН УКАЗАТЕЛЮ song.
Т.е. где-то должен быть такой код:
Цитата

module m; //создали неинициализированную структуру
xm.song=&m;

Если он есть, то ИМХО все OK. (Попробуй поискать).

Цитата

Решение заключается в том, чтобы указатель получил какой-то реальный адрес, а именно вот так: module* song[1];
после этого можно обращаться к полям структуры module в структуре sound_struct.

Ты просто создал массив из одного элемента типа module*. Возможно ты этим просто отбил деббагеру охоту ругаться. На внутренне уровне ничего не изменилось. Но он не получит "реальный адрес" структуры module сам по себе, если ее нету! - Это же просто указатель. Обязательно должно быть где-то: module m; xm.song=&m;

В общем ИМХО тут все OK... smile
P.S. open source говоришь? А можно ссылку на эти исходники? ;)

Это сообщение отредактировал(а) LPBOY - 7.8.2005, 03:03
--------------------
Каждый человек по-своему прав, а по-моему нет...
PM MAIL   Вверх
Profi80
Дата 8.8.2005, 01:03 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Вот в том то и дело, что структура module нигде не инициализирована! Всё было бы понятно, если бы где-нибудь была инициализация. Но я её нигде не нашёл - поэтому и возник этот вопрос! А на самом деле, когда создал массив из одного элемента module, появилась другая проблема - память в структуре sound_struct выделилась в размере 4 байта (как раз под адрес), и просле чтения из файла данные после первых четырёх байт записались в соседнюю структуру channels. Так что решение не помогло...
smile

Всё-таки я не понимаю как это должно работать... smile

Вот, можешь посмотреть сам исходники:


Исходники
  Вверх
Profi80
Дата 8.8.2005, 01:12 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











Извиняюсь, опечатка была. Я хотел сказать, что структура нигде не создана. Т.е. нигде нет кода типа module m; xm.song=&m;

Устал сегодня, опять ковырял код... Надо же постараться так написать, что потом ничего не разберешь.. smile
  Вверх
Romikgy
Дата 8.8.2005, 08:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Любитель-программер
****


Профиль
Группа: Участник Клуба
Сообщений: 7326
Регистрация: 11.5.2005
Где: Porto Franco Odes sa

Репутация: 8
Всего: 146



Я не полностью разбирался, но там где -то должен быть вызов функции sound_stream_init(), в ней есть еще одна функция
Код

void new_song(sound_struct *xm) 

И вот в реализации этой функции:
Код

song = (module*) mem_new( 0, sizeof( module ), "song", 0 );// Вот здеся и инициилизируется место под структуру :)
    xm->song = (module*) ByteSwap32( song );
    //clear new song:
    for(a=0;a<128;a++) song->instruments[a] = 0;
    for(a=0;a<256;a++) song->patterns[a] = 0; 



--------------------
Владение русской орфографией это как владение кунг-фу — истинные мастера не применяют его без надобности. 
smile

PM   Вверх
LPBOY
Дата 8.8.2005, 09:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 228
Регистрация: 12.7.2005

Репутация: 20
Всего: 20



2Romikgy, точно smile Память выделяется динамически, а не статически как я думал.
Но главное, что она выделяется smile

2Profi80 Скачал исходник, все скомпилировалось и запустилось.
Единственное что я изменил - раскомментировал дефайны
Код

#define COLOR32BITS
#define NONPALM
#define WIN
#define DIRECTX 

а остальные закомментировал (в core.h). - Это было написано в документации (для win32).
Компилировал на MSVC 7.1 (там и проект для VC6 лежал, поэтому проблем не возникло).
Думаю, тут дело не в ошибках в программе, а в переносе на другой компилятор...

Это сообщение отредактировал(а) LPBOY - 8.8.2005, 09:57
--------------------
Каждый человек по-своему прав, а по-моему нет...
PM MAIL   Вверх
Profi80
Дата 8.8.2005, 13:49 (ссылка)    |    (голосов: 0) Загрузка ... Загрузка ... Быстрая цитата Цитата


Unregistered











А я не под Win32 компилирую, а под Palm OS 5.4.
В Codewarrior 9 не компилируется (если без Armlet-ов), линкер ругается...
Наверное действительно дело в компиляторе...

To Romikgy я наверное не в той последовательности код смотрел, полагал что sound_stream_init() вызывается позже, а видимо наоборот - спасибо что подсказал!
  Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0503 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.