Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Динамический массив

30K
30 ноября 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Здравствуйте. Суть моей проблемы такова:
Есть класс, который имеет в своем составе члены стандартных типов int и char, а также члены-структуры мною созданные.

Код:
public class DATA_SM  {
public: char service_type[6];
        int1 source_addr_npi;
        char source_addr[65];
        int1 dest_addr_ton;
        int1 dest_addr_npi;
        char  destination_addr[65];
        int1 esm_class;
        TLV source_port;
        TLV source_addr_subunit;
        };

Int1 - это ппросто переименованный unsigned char - мне так удобнее.

Здесь у меня с символьными строками все в порядке - имеют максимальный фмксированный размер.
Структура TLV:

 
Код:
public struct TLV  {
        short Tag;
        short Length;
//      Byte Value[2];
};


Так вот - суть проблемы: Мне необходимо измерять переменные типа DATA_SM в байтах, например так:
 
Код:
DATA_SM A;
int b=sizeof(A);

НО, я не знаю как сделать так чтобы массив байт Value в TLV был нефиксированного размера и при этом измерение было правильным. ПО идее надо использовать указатель, но тогда sizeof вернет неверный размер. (Размер указателя 4 байта.)
Если использовать strcpy(), значение копируется, а вот размер массива остается прежним.

 
Код:
TLV var1;
char val[]="valueeeee";
strspy(var1.Value, val);

Вероятно здесь я не понимаю до конца как работает память с переменными и что-то там связанное со стэком.
Подскажите пожалуйста кто может как поступить. ПРосто иначе придется сделать массив фиксированного размера)))
30K
30 ноября 2011 года
Gaidukov-maxim
28 / / 25.02.2008
ПОчему написал здесь - из-за альтернативного варианта. Использовать управляемые классы и Marshal::SizeOf(). Но что-то с эти маршалом даже простой пример не получается - постоянно ошибки лезут.
278
30 ноября 2011 года
Alexander92
1.1K / / 04.08.2008
А почему не сделать в структуре дополнительное поле - размер структуры? Так, как это в WinAPI делается, к примеру, когда структура может содержать данные переменной длины.
30K
30 ноября 2011 года
Gaidukov-maxim
28 / / 25.02.2008
А как sizeof учтет этот размер, когда будет мерить?

 
Код:
DATA_SM A;
int b=sizeof(A);


КОнечно как вариант - сделать функцию, которая будем мерить размер переменной типа DATA_SM, складывая размеры полей и поля,хранщие размеры структурных полей. Но класс DATA_SM один из 20 с копейками, которые отличаются друг от друга названием полей и их количеством. Поэтому как-то слишком мануально получается.
278
30 ноября 2011 года
Alexander92
1.1K / / 04.08.2008
А никак sizeof не будет мерить, я ж и говорю - откажитесь от sizeof и указывайте размер вручную. Каждый раз, когда вы меняете TLV::Value, указываете вручную соответствующее поле в структуре. Это абсолютно принятая практика.
30K
01 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Это конечно не очень приятно, т.к. много классов, которые включают в себя более двух десятков полей, в том числе TLV полей. Но даже при таком решении - как определить размер массива Value в байтах по указателю?

 
Код:
public struct TLV  {
        short Tag;
        short Length;
        Byte* Value;
};

Хм... Я так полагаю, что определить его можно по массиву, на который ссылается этот указатель.
 
Код:
TLV var1;
char val[]="valueeeee";
strspy(var1.Value, val);
var1.Length=sizeof(val);
260
01 декабря 2011 года
Ramon
1.1K / / 16.08.2003
Внимание вопрос: Что есть sizeof и когда он вычисляет размер (на момент препроцессинга/компиляции/линковки/запуска или исполнения приложения)?
30K
01 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Интересный момент, нашел в мсдн:
If an unsized array is the last element of a structure, the sizeof operator returns the size of the structure without the array.
Скорее всего во время выполнения. Хотя надо уточнить...
240
01 декабря 2011 года
aks
2.5K / / 14.07.2006
Нет. Через sizeof можно узнать только константно заданный размер массива . После приведения к указателю - размер вы уже никак не узнаете. Только размер указателя (4, 8 байт и т.п. в зависимости от разрядности). Всегда, когда вы работаете с указателем на какой то буфер в памяти, нужно вместе с ним передавать размер, ибо по другому его не узнать.
И вы в конце концов определитесь что вам надо: размер структуры в терминах языка или же размер какого то пакета данных, представляемых структурой, допустим для сериализации? Храните размер буфера в структурах, в чем сложность то? Не хотите - храните вобще контейнеры. Например std:vector. Он вам предоставит и интерфейс массива и сам будет следить за размером и хранить его.
30K
01 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Пример не приведу. Но часто встречается, что sizeof() измеряет размер введенной с клавиатуры символьной строки. Значит размер вычисляется во время выполнения программы.
30K
01 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Вечером попробую шире описать свой проект и в чем я вижу проблему. Я просто начал с простого, стого, что мне надо какой-то динамический массив, который можно измерить при помощи sizeof и чтобы никаких указателей и vector, ListArray и чего то подобного. Потому единичный элемент массива в них занимает не 1 байт. А мне нужно хранить данные именно в байтовом массиве, чистые данные в байт массиве, и без какой либо информации о структуре массива(vector).
260
01 декабря 2011 года
Ramon
1.1K / / 16.08.2003
Цитата: Gaidukov-maxim
Пример не приведу. Но часто встречается, что sizeof() измеряет размер введенной с клавиатуры символьной строки. Значит размер вычисляется во время выполнения программы.



Найдите такой пример и приведите его, многие тайны откроются вам.

30K
01 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Немножко подробнее....

 
Код:
public struct TLV  {
        short Tag;
        short Length; \\хранит размер Value в байтах
        Byte Value[2]; \\данные неизвестного типа и размера помещаются сюда ввиде байт-массива.    Зависит не от меня, а отпараметров сервера, которому все передается
};


Код:
public class DATA_SM  {
public:     short Length; //здесь помещается размер переменной типа DATA_SM (в байтах)
            char service_type[6];
            Byte source_addr_npi;
        char source_addr[65];
        Byte dest_addr_ton;
        Byte dest_addr_npi;
        char  destination_addr[65];
        Byte esm_class;
        TLV source_port;
        TLV source_addr_subunit;
            Byte[] ToByteArray(); //тут бред, пока не занимался реализацией этой функции
        };


Я хочу отправлять ввиде массива байтов перменную типа DATA_SM
например так:
 
Код:
Socket sc;
DATA_SM A; //без  new наверное будет если внутри нет указателей
.
.
.
A.Length=sizeof(A.ToByteArray());
sc->Send(A.ToByteArray());
....


Т.е. получаем что размер и содержимое связаны и соответсвуют друг другу.
ВОт приблизительно так...... Надеюсь более менее понятно.
240
02 декабря 2011 года
aks
2.5K / / 14.07.2006
Цитата: Gaidukov-maxim
Пример не приведу. Но часто встречается, что sizeof() измеряет размер введенной с клавиатуры символьной строки. Значит размер вычисляется во время выполнения программы.


Ну или пример с ошибкой или вы не правильно поняли зачем там применяется sizeof. Встретите такой код - несите сюда, тут и разберем.

Цитата: Gaidukov-maxim
Немножко подробнее....


Я посмотрел и так и не понял зачем вам тут sizeof. Тут обычная сериализации объекта. Для всех динамически выделяемых массивов в любом случае надо хранить их длину. Ну или хранить векторы. Из вектора всегда можно получить указатель на данные и они там гарантировано лежат в одном последовательном буфере. Что то у меня такое ощущение что мы на разных языках говорим и немного друг друга не понимаем. =)

30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Согласен. С вводом массива я заблуждался.:facepalm:
Небольшое отвлечение. Вот такой пример:

 
Код:
char a[]="aaaaa";
char b[]="bbbbbbbb";
strcpy(a,b);
int c =sizeof(a);
String^ d=new String(a);
TextRichBox1->Text=c.ToString +"----"+ d;


Получаем "6----bbbbbbbb" Т.е. значение скопировалось, а размер остался прежним.
Не могу понять чем это объясняется?

И насчет sizeof() почитал. Типы оказывается мерить не так просто...
http://www.cyberguru.ru/programming/cpp/cpp-programming-guide-page24.html
Там похоже есть ошибка, но суть ясна. Пробовал мерить - длина не соответсвует посчитанному руками.
Я так понимаю, все на самом деле сложнее, чем мне казалось с отправкой данных. Может кто подскажет в каком направлении плясать? Какие методы использовать?
240
02 декабря 2011 года
aks
2.5K / / 14.07.2006
Цитата: Gaidukov-maxim

Небольшое отвлечение. Вот такой пример:
 
Код:
char a[]="aaaaa";
char b[]="bbbbbbbb";
strcpy(a,b);
int c =sizeof(a);
String^ d=new String(a);
TextRichBox1->Text=c.ToString +"----"+ d;

Получаем "6----bbbbbbbb" Т.е. значение скопировалось, а размер остался прежним.
Не могу понять чем это объясняется?


Этот пример некорректный и не рабочий в общем случае. Потому как у массвов a и b неправильно указаны типы. Правильно было бы инициализировать так:

 
Код:
const char a[] = "aaaaa";
const char b[] = "bbbbbbb";

Но из-за того что в c++ порой допускается такое неявное преобразование указателей при инициализации с константных в не константные и возникает проблема. В частности, поскольку a изначально константный - туда нельзя ничего писать. И в некоторых случая, а на ряде компиляторов - всегда, на этой записи у вас программа просто упадет. Если бы вы сразу описали тип массива как const char - тогда компилятор просто не скомпилировался бы на вызове strcpy, и подсказал бы об ошибке. А так, вы мало того что записали в память, в которую нельзя писать, так еще и вылезли за её пределы и записали остаток второй строки в чужую память, где могли находиться какие то объекты программы да и просто служебная информация. Таким образом программа принимает не рабочее состояние и в любой момент может начать вести себя совершенно случайным образом. ) При этом размер массива a конечно же никуда не менялся, просто вылезли за его пределы.

Цитата: Gaidukov-maxim

насчет sizeof() почитал. Типы оказывается мерить не так просто...
http://www.cyberguru.ru/programming/cpp/cpp-programming-guide-page24.html
Там похоже есть ошибка, но суть ясна. Пробовал мерить - длина не соответсвует посчитанному руками.
Я так понимаю, все на самом деле сложнее, чем мне казалось с отправкой данных. Может кто подскажет в каком направлении плясать? Какие методы использовать?


Да не надо никуда плясать - все ведь уже сказано. Не надо ничего мерить - для всех массивов просто всегда надо хранить их размер. Размер атомарных типов можно уже вычислять через sizeof. Хотя тоже на самом деле не желательно, если вы пишите какую то сетевую софтину (судя по коду). Потому что тогда данные ушедшие в сеть будут зависеть от вашего компилятора, операционной системы, разрядности процессора и т.п.
А надо сначала определить размерности всех ваших числовых полей в пакетах, в tlv вашего протокола. Определить порядок байт в них - это тоже немаловажно, порядок на вашей машине и удаленной может различаться. Кодировки строк и прочее - все это определить в спецификации протокола. И только потом, уже записывая очереной объект в сеть, в файл, в просто какой то абстрактный поток данных - вы приводите свои поля к виду определенному в протоколе. Массивы соответственно пишите как есть, если внутри них данные не подлежат конвертации. Для всех массивов у вас должны быть размеры и все.

30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
 
Код:
const char a[] = "aaaaa";
const char b[] = "bbbbbbb";

В таком случае константно содержимое массива? А если сначала задается, например, значение по умолчание. А в дальнейшем будет необходимость его изменить?

Насчет протокола - да. поля идут друг за другом по спецификации - в том самом порядке. Допустим все размеры всех массивов char у меня заданы. Суммарный Размер всех полей атомарных типов посчитаю и запишу куда надо.
Затем, как мне лучше отправить сокетом на сервер? Преобразовть в массив байт? Какими методами это делать лучше? Про эти плясать я и спрашивал.
297
02 декабря 2011 года
koodeer
1.2K / / 02.05.2009
Цитата: Gaidukov-maxim
 
Код:
char a[]="aaaaa";
char b[]="bbbbbbbb";
strcpy(a,b);
int c =sizeof(a);
String^ d=new String(a);
TextRichBox1->Text=c.ToString +"----"+ d;


Э-эх... Какая каша у вас. Тут и строки в стиле Си, и попытки работать с ними, как со строками C++, и в довершение C++.NET.
Про строки в стиле Си aks уже расписал, в чём ваша ошибка.
Последние две строки вашего кода: это из C++.NET. Значок ^ - это управляемый указатель. Метод ToString - тоже из управляемого кода. Ну и ричтекстбокc без всякого сомнения из WinForms.
В первую очередь вам нужно понять, что C, C++, и C++.NET - это по сути три разных языка. Да, в Visual Studio их можно смешивать. Но лучше этого не делать! Во всяком случае, нужно понимать, когда и зачем это делается. Именно по этой причине я считаю VS крайне неудачным выбором для начинающих осваивать C/C++. Новички постоянно путаются и делают кровавое месиво из разных технологий (как и я в своё время...)

Короче: чтобы освоить чистый Си, нужно взять K&R и включить компиляцию проекта именно как чистый Си. Тогда среда разработки не позволит использовать С++.
Чтобы освоить нативный С++, нужно ни в коем случае не использовать управляемые возможности среды .NET. В частности, WinForms. А если хочется именно формочки легко клепать, то лучше перейти на C#.

240
02 декабря 2011 года
aks
2.5K / / 14.07.2006
Цитата: Gaidukov-maxim

Суммарный Размер всех полей атомарных типов посчитаю и запишу куда надо.


Повторюсь - надо не просто посчитать их размер, чтоб размер отправляемого вами в сеть зависел от размера полей, а наоборот. Надо привести ваши поля к виду описанному в протоколе. Например в протоколе указано что в вашем tlv поля тип и длина должны быть 4-х байтовыми целыми в сетевом порядке байт. А на вашем конкретном компьютере и ОС оказывается эти поля в структурах C++ 8-ми байтовые. Значит надо сделать так, чтоб или в структурах всегда были 4-х байтовые типы или переводить их в 4 байта перед отправкой. А затем перевести их в сетевой порядок байт, если они в обратном порядке.

Цитата: Gaidukov-maxim

Затем, как мне лучше отправить сокетом на сервер? Преобразовть в массив байт? Какими методами это делать лучше? Про эти плясать я и спрашивал.


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

30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Цитата: koodeer
Э-эх... Какая каша у вас. Тут и строки в стиле Си, и попытки работать с ними, как со строками C++, и в довершение C++.NET.
Про строки в стиле Си aks уже расписал, в чём ваша ошибка.
Последние две строки вашего кода: это из C++.NET. Значок ^ - это управляемый указатель. Метод ToString - тоже из управляемого кода. Ну и ричтекстбокc без всякого сомнения из WinForms.
В первую очередь вам нужно понять, что C, C++, и C++.NET - это по сути три разных языка. Да, в Visual Studio их можно смешивать. Но лучше этого не делать! Во всяком случае, нужно понимать, когда и зачем это делается. Именно по этой причине я считаю VS крайне неудачным выбором для начинающих осваивать C/C++. Новички постоянно путаются и делают кровавое месиво из разных технологий (как и я в своё время...)

Короче: чтобы освоить чистый Си, нужно взять K&R и включить компиляцию проекта именно как чистый Си. Тогда среда разработки не позволит использовать С++.
Чтобы освоить нативный С++, нужно ни в коем случае не использовать управляемые возможности среды .NET. В частности, WinForms. А если хочется именно формочки легко клепать, то лучше перейти на C#.



Я понимаю, что каша. Просто я привел, возможно, не удачный пример. Пока я ориентирован на создание Windows Forms Application. А С-шные типы использую, чтобы осуществлять манипуляции с обработкой и отправкой данных. Спасибо за замечание. Буду стараться делать делать все в одном стиле. Но пока я вот так делаю. И вообще потом реализовать прогу хочу на WinAPi, а сейчас как-то реализовать функционал таким образом. Потому как с API я вообще не практиковался.

30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Цитата: aks
Повторюсь - надо не просто посчитать их размер, чтоб размер отправляемого вами в сеть зависел от размера полей, а наоборот. Надо привести ваши поля к виду описанному в протоколе. Например в протоколе указано что в вашем tlv поля тип и длина должны быть 4-х байтовыми целыми в сетевом порядке байт. А на вашем конкретном компьютере и ОС оказывается эти поля в структурах C++ 8-ми байтовые. Значит надо сделать так, чтоб или в структурах всегда были 4-х байтовые типы или переводить их в 4 байта перед отправкой. А затем перевести их в сетевой порядок байт, если они в обратном порядке.
.


Ну пока я принимаю, что компьютер только мой и ОС только моя - 32 бита. Просто хочу получить простой работоспособный функционал. Без всяких "а если...." Это все потом. Пока алгоритм.

240
02 декабря 2011 года
aks
2.5K / / 14.07.2006
Тут даже не в стилях дело. Вы используете три разных языка в одном коде (если C и С++ еще как то близки по концепции, то C++.Net вобще далек от них ), и совершенно разные технологии. Так действительно лучше не делать ибо проблем намного больше чем выгод.
30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Цитата: aks


Как вариант прямо внутри сериализующей функции - мелкие поля посылать не по одиночке, а сливать в некий буфер, который послать разом, чтобы работало быстрее.


Вот вот вот. Так я себе это и представляю. Подскажите, пожалуйста, какие инструменты для этого существуют?

240
02 декабря 2011 года
aks
2.5K / / 14.07.2006
Цитата: Gaidukov-maxim
Ну пока я принимаю, что компьютер только мой и ОС только моя - 32 бита. Просто хочу получить простой работоспособный функционал. Без всяких "а если...." Это все потом. Пока алгоритм.


В том то и дело, что нету никакого алгоритма. Нужно просто отсылать все поля в сеть. По порядку. Алгоритмом это язык назвать не поворачивается. Разве что алгоритм из одного действия. =)
Чтоб потом не огребать геммороя - лучше сразу их конвертировать в протокольный вид. Это не сложно и это делается сразу одновременно с отправкой.

30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Цитата: aks
В том то и дело, что нету никакого алгоритма. Нужно просто отсылать все поля в сеть. По порядку. Алгоритмом это язык назвать не поворачивается. Разве что алгоритм из одного действия. =)
Чтоб потом не огребать геммороя - лучше сразу их конвертировать в протокольный вид. Это не сложно и это делается сразу одновременно с отправкой.



Я представляю реализацию так:
1. Определить нужные типы данных с использованием атомарных типов( ПО спецификации). Т.к. они представляют собой пакеты обмена.
2. Функции работы с ним и(Инициализации, конвертирования и пр.). (Тут наверно и стоит выбрать язык). Допустим .Net
2. Осуществление обмена с сервером (подключение, очередь пакетов и пр.)
3. Создать интерфейс программы.

Можно конечно идти в обратном направлении....

240
02 декабря 2011 года
aks
2.5K / / 14.07.2006
Цитата: Gaidukov-maxim
Вот вот вот. Так я себе это и представляю. Подскажите, пожалуйста, какие инструменты для этого существуют?



Да никаких инструментов, кроме самого языка - просто пишете в массив и все.
Тоесть допустим у вас есть спецификация пакета протокола:
field1 - целое 4 байта.
field2 - целое 8 байта.
...
fieldN - целое 4 байта
dataLengh - длина массива, целое 8 байт. итого все эти поля M байт.
data - массив байт длиной dataLengh

тогда код что то типа такого:

Код:
static const size_t HEADER_SIZE = M;
char header[HEADER_SIZE]; /// или char * header = new char[HEADER_SIZE];

char * ptr = header;
netField1 = преобразовать_в_сетевой_вид(field1);
memcpy(ptr, &netField1, размер_netField1);
ptr += размер_netField1;
...
netDataSize = преобразовать_в_сетевой_вид(dataSize);
memcpy(ptr, &netFieldN, размер_netDataSize);
ptr += размер_netDataSize;

stream.write(header, HEADER_SIZE);
stream.write(data, dataSize);


естественно все можно написать более компактно - я развернуто на частично псевдокоде расписал чтоб было понятней. =)
30K
02 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Спасибо. Вечером попробую что-то такое. На работе просто не на чем.
30K
05 декабря 2011 года
Gaidukov-maxim
28 / / 25.02.2008
Вроде начало двигаться)).
Вот такие дела приблизительно получились:
public struct TLV {
Код:
public: short Tag;
        short Length;
        Byte* Value;

        TLV( short tag, size_t LengthOfTypeValue, void* value) //конструктор
        {
            this->Tag=tag;
            this->Length= (short)LengthOfTypeValue;
            this->Value=(Byte*)value;
        }
};


Далее:
Код:
public class DATA_SM {
public: int command_length;
        int command_id;
        int command_status;
        int sequence_number;
        Byte* ptr_array;
char system_id[16];
        TLV sc_interface_version;
        void ToByteArray ()
        this->command_length=sizeof(command_length)+sizeof(command_id)+sizeof(command_status)+
        sizeof(sequence_number)+sizeof(system_id)+ sizeof(sc_interface_version.Tag)+
        sizeof(sc_interface_version.Length)+ sc_interface_version.Length; //подсчет размера пакета
        static const size_t BUFER_SIZE=command_length;
        static Byte* bufer = new Byte[BUFER_SIZE];
        Byte* ptr = bufer;
        memcpy(ptr, &command_length, sizeof(command_length)); //складывание таким образом всех полей
        ptr += sizeof(command_length);
        memcpy(ptr, &command_id, sizeof(command_id));
        ptr += sizeof(command_id);
        memcpy(ptr, &command_status, sizeof(command_status));
        ptr += sizeof(command_status);
        memcpy(ptr, &sequence_number, sizeof(sequence_number));
        ptr += sizeof(sequence_number);
        memcpy(ptr, system_id, sizeof(system_id));
        ptr += sizeof(system_id);
        //sc_interface_version
        memcpy(ptr, &sc_interface_version.Tag, sizeof(sc_interface_version.Tag));
        ptr += sizeof(sc_interface_version.Tag);
        memcpy(ptr, &sc_interface_version.Length, sizeof(sc_interface_version.Length));
        ptr += sizeof(sc_interface_version.Length);
        memcpy(ptr, sc_interface_version.Value, sc_interface_version.Length);
        ptr += sizeof(sc_interface_version.Length);
        this->ptr_array=bufer;
        }
};

Ну и далее с указателем на массив байт проводим последующие преобразовния и отправку через сокет. Надеюсь что-то получится. Aks огромное спасибо.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог