Russian Qt Forum
Ноябрь 22, 2024, 23:25 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: 1 [2]   Вниз
  Печать  
Автор Тема: Можно ли преобразовать struct в const char*?  (Прочитано 15786 раз)
Vld2
Гость
« Ответ #15 : Декабрь 18, 2006, 21:19 »

Код работает под виндой, для линуха небольшие исправления в сетевой части.
Записан
Вудруф
Гость
« Ответ #16 : Декабрь 19, 2006, 08:11 »

Receive.cpp
Код:

char *Ptr = new char; //выделили один символ из кучи (указатель Ptr)
struct black_ice          //объявляем структуру, имеющую размер не менее 1002-х байт
{
  char str[MAX_LEN];
  short int  len;
};

black_ice* ptr= new black_ice;  //теперь выделяем эти самые 1002 байта из кучи (указатель ptr)
ptr = (black_ice*)(void*)Ptr;  //Оп-па! Ошибка! Мы присваиваем указателю ptr новый адрес, указывающий на место, где выделен всего 1 (один!) байт, а пользуемся аж 1002-мя. Иными словами, не гарантируется, что 1001 байт не затрётся в другом месте программы.


Надеюсь, всё понятно?

добавлено спустя 13 минут:

 Ну и к тому же, налицо утечка памяти. В receive.cpp это black_ice (1002 байта потеряно), в send.cpp это char (один байт).
Зачем вообще его выделять из кучи, для указателя вовсе не требуется инициализатор.

Поскольку единственное преобразование в send.cpp, это send (sock, Ptr2,ptr2->len, 0)), то вообще не имеет смысла определять новый указатель. Делаем так:
Код:
send (sock, ptr2->str, ptr2->len, 0);


Аналогично и в receive.cpp. Тут вообще не надо преобразовывать указатель на структуру к char *.
Далее, если действительно при вызове какой-то функции нужно преобразовывать указатели, то и делай это в месте вызова, пользуясь cast-стилем приведения.

P.S. Действительно, а причём здесь Qt?
Записан
Vld2
Гость
« Ответ #17 : Декабрь 20, 2006, 20:03 »

Вудруф,
Цитировать

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

По другому в этой программе не пашет.
Цитировать

send (sock, ptr2->str, ptr2->len, 0);

не понял на счёт ptr2->str, Мне нужно передать структуру ( то есть поля int и char). Как можно обойтись только ptr2->str?
Цитировать

P.S. Действительно, а причём здесь Qt?

На Qt графическая часть, пока до неё не дошел.
Цитировать
char buf[1];
strcpy(buf, "123456789");

Самое интересное что в buf будет лежать 123456789, хотя он расчитан для 2 элементов. Не усекается почемуто.
Код работает, но возможны утечки памяти.
Записан
Dendy
Гость
« Ответ #18 : Декабрь 20, 2006, 21:21 »

Мне вот одного непонятно...
На кой чёрт юзать помесь Си с плюсами и WinAPI, если гуёвая часть всё равно на Qt. Qt Desktop Edition содержит в себе Network. Так почему бьІ не заюзать вьІсокоуровневьІе QTcpSocket, QDataStream, QByteArray и прочие елементарньІе классьІ для работьІ с сетью? Код получился бьІ в три раза короче, в 5 раз понятней для любого китайца и в N (где N стремится к M) функциональней. А проблемьІ с "возможны утечки памяти" отпали бьІ сами собой.
Записан
Вудруф
Гость
« Ответ #19 : Декабрь 20, 2006, 21:47 »

Так, поехали:
Цитировать
По другому в этой программе не пашет.

Не аргумент! Ошибка в другом месте, иначе это приводит к работоспособности только здесь и сейчас.
Цитировать
Мне нужно передать структуру ( то есть поля int и char). Как можно обойтись только ptr2->str?

Тебе, похоже, нужно передать только строку? Зачем в этом случае передавать всю структуру?
Далее, если тебе нужно передать действительно класс, то делается это так:
Код:
send (sock, static_cast <void *> (ptr), sizeof (black_ice), 0);

Где ptr - указатель на структуру.

Но и это неправильно! Ты не можешь быть уверенным, что на клиенте структура будет в памяти представлена таким же образом. Иными словами, ты сам должен придумать формат обмена, и заполнять передаваемый буфер ручками.
Обычно такой гемор не нужен, так что делают обёртки (см. ООП).

Цитировать
На Qt графическая часть, пока до неё не дошел.

Вот когда дошёл бы, тогда и писал бы на разделе Qt. А такие вопросы надо было задавать в разделе C++.
Или ты собрался все вопросы задавать в одной теме? Тебе никто не будет тогда отвечать.

Цитировать
char buf[1];
strcpy(buf, "123456789");
Самое интересное что в buf будет лежать 123456789, хотя он расчитан для 2 элементов. Не усекается почему-то.

Логично, чёрт побери. strcpy объявлена так:
Код:
void strcpy (char *, const char *)

Ты копируешь в память по указателю. Откуда компилятор должен знать размер памяти, в которую ты копируешь?
Не надо говорить про то, что ты объявил массив. Объявлением массива ты всего лишь выделяешь локальную память. Если бы встроенные массивы отслеживали длину, то здесь бы терялась производительность.
Если нужны расширяемые контейнеры - смотри в сторону STL. Например, std::vector.

Цитировать
Код работает, но возможны утечки памяти.

Это тебе не Java, здесь сборки мусора нет. Учись писать сразу правильно.

По твоему коду:
RECEIVE.cpp
Код:
char *Ptr = new char[sizeof(black_ice)];

Ещё раз говорю, просто
Код:
char * Ptr;
Аналогично и в SEND.CPP

Код:
char *Ptr = new char[sizeof(black_ice)];
black_ice* ptr= new black_ice;
memset(ptr->str,0,81);    
ptr = (black_ice*)(void*)Ptr;

Мы выделяем память, инициализируем её, а потом просто выбрасываем!
Может, надо
Код:
Ptr = (black_ice*)(void*)ptr;

Вот ещё один пример, что переменные надо нормально называть. Впрочем, в данном случае инициализация вообще не нужна.

Код:
QString tut;

Зачем?

У тебя в коде слишком много лишнего. Лишние указатели, лишние строки (память, память!), лишние действия.
Извини, но на работе мы с сотоварищами просто по столу катались. Ты уж не обижайся.

P.S. Ей-богу, прочитай сначала любую книгу по Си++. Лучше всего - Страуструпа. А ты и Си толком не знаешь.
P.P.S. Если ты собрался GUI делать на Qt, то зачем тогда пользоваться низкоуровневыми средствами для работы с сетью?
P.P.P.S. Глупых вопросов больше не задавай. Как говорят, RTFM! Хотя бы чего-нибудь по Си++...
Записан
Vld2
Гость
« Ответ #20 : Декабрь 21, 2006, 21:17 »

Вудруф,
Цитировать

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

А если я делаю клиент и сервер, то соответсвенно сам и размещаю структуру. проблем не должно быть.
Цитировать

У тебя в коде слишком много лишнего. Лишние указатели, лишние строки (память, память!), лишние действия.
Не спорю некотрые факты передернул.
Цитировать

Если ты собрался GUI делать на Qt, то зачем тогда пользоваться низкоуровневыми средствами для работы с сетью?
На одном qt нельзя останавливаться, должен быть всесторонний охват в смежных языках. Сегодня на Qt работаешь, а завтра неизвестно на чем?
Цитировать

send (sock, static_cast <void *> (ptr), sizeof (black_ice), 0);

тут или два раза надо использовать static_cast, так как нам нужен char * (для wind).  И намного ли хуже использовать обычное приведение (void *), статическое ?
Записан
Вудруф
Гость
« Ответ #21 : Декабрь 22, 2006, 08:17 »

Цитировать
А если я делаю клиент и сервер, то соответсвенно сам и размещаю структуру. проблем не должно быть.

Проблемы могут быть, т.к. ты компилируешь сервер и клиент раздельно. Чуть изменил настройки оптимизации, перешёл на другую версию компилятора - всё перестанет работать!

Цитировать
должен быть всесторонний охват в смежных языках

Qt - это не язык Улыбающийся Это библиотека.
А низкоуровневые средства для работы с сетью применять не обязательно. Уже существует достаточно много высокоуровневых обёрток над сетевым кодом.

Цитировать
Сегодня на Qt работаешь, а завтра неизвестно на чем?

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

Цитировать
И намного ли хуже использовать обычное приведение (void *) вместо статического

Приведение требуется достаточно редко. Именно поэтому в Си++ сделан такой "неудобный" стиль приведения.
Используя Си-стиль (со скобочками), нельзя быть уверенным, какое именно приведение будет выбрано (static, reinterpret...).

Цитировать
нам нужен char *

Тут я смотрел man send, а там указатели void * Улыбающийся
Да, в таком случае действительно будет два static_cast. И такая "неудобная" запись будет обращать внимание на потенциально опасный участок кода.
Записан
Vld2
Гость
« Ответ #22 : Декабрь 25, 2006, 11:32 »

Вудруф,
Цитировать

Проблемы могут быть, т.к. ты компилируешь сервер и клиент раздельно. Чуть изменил настройки оптимизации, перешёл на другую версию компилятора - всё перестанет работать!

Если в клиенте задать структуру:
struct
{ char
 int
}
а на сервере:
str
{int
char} , то конечно не пашет правильно.
Но я все-таки вначале ложу большее по размеру значение, а потом меньшее. В итоге выравнивания памяти не происходит. Нет выравнивания, нет проблем. Ради интереса проверю этот код ещё и под solaris и linux.
Цитировать

Qt - это не язык  Это библиотека.
А низкоуровневые средства для работы с сетью применять не обязательно. Уже существует достаточно много высокоуровневых обёрток над сетевым кодом.

Начинать надо снизу, чтобы прийти вверх.
Цитировать

Используя Си-стиль (со скобочками), нельзя быть уверенным, какое именно приведение будет выбрано (static, reinterpret...).

В доках написано, что static и reinterpret ничего не гарантируют. Зачем они нужны если нет гарантии?
Записан
Dendy
Гость
« Ответ #23 : Декабрь 25, 2006, 12:20 »

Задашь тьІ одинаковую структуру, а размер int на системах будет стоять разньІй. Дальше - вьІравнивание там 1 байт, здесь 8 байт. А для полного екстаза скомпилируй всё ето под PowerPC на Макинтоше, где подяток байт BigEndian, в структуре получишь лапшу. И будешь долго искать какие костьІли ещё прикрутить.

Задачу нужно решать максимально еффективньІм способом. А не по принципу: заюзаю здесь библиотеку А, потому что она пригодится в другом проекте. А в другом проекте заюзать всё таки Б, потому что неплохо изучить для применения в проекте ЬІ. И так далее. Задачи нужно решать. Чтоб работали и есть не просили.

Когда понадобится - тогда и изучишь. На примере "Hello, World!". Конечно же если то, что тьІ сейчас делаешь и есть изучение сети, то вопросов нет. Тренируйся наступать на грабли.

Но советую посмотреть в сторону QDataStream, потому как содержит правильную идеологию и реализацию передачи данньІх между платформами.
Записан
Вудруф
Гость
« Ответ #24 : Декабрь 25, 2006, 12:31 »

Кроме того, мне кажется, что компиляторы могут менять порядок следования членов в структуре/классе...
Записан
kotofay
Гость
« Ответ #25 : Декабрь 25, 2006, 13:41 »

Цитата: "Vld2"
Конвертация прошла успешна, за исключением того что в char записывает лишний символ.
struct mine
{ int i;
   char[50];
}
Посылаю например "qt", а получаю "qtA" , где А - любой символ. Бывает дописывает даже 2 или 3 символа. Хотя посылаемый и получаемый размер одинаков. В чем может быть проблема? И как выравнивать структуру в памяти.


Попробуй перед использованием массива очистить память.
Записан
Страниц: 1 [2]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.055 секунд. Запросов: 20.