C++, по указателю разместить в памяти разнотипные данные
структурой
Если структурой нельзя из-за того, что порядок и количество даных не известно во время компиляции, то надо сначала приводить указатель к типу (void* потом прибавлять смещение, а потом уже приводить к нужному типу. Но тут возможны проблемы с выравниванием и надо быть очень аккуратным.
ыыыы, я был невнимателен.
Мб union спасет отца русской демократии? А вообще просто не надо так писать и все. Если надо, могу не поленится привести ссылку на (бумажную) книгу Герба Саттера, где этот вопрос подробно разбирается.
+1 за union или struct.
самба использует свои извратные макросы, лежат в byteorder.h
а откуда могут свалится флоаты в блоке? их вроде-как не принято по сети гонять в таком виде.
их вроде-как не принято по сети гонять в таком виде.\
По сети и не гоняю, это на одной машине делается.
А вообще до struct я и сам додумался, и вобщем там структы и перегоняются, но проблема всеже в том, что перегоняются два блока данных, каждый неизвестного заранее размера. Вобщем примерно было так:
struct node
{
long m_id;
unsigned char m_color_r;
unsigned char m_color_g;
unsigned char m_color_b;
float m_x;
float m_y;
float m_z;
}
struct node_connection
{
long m_id1;
long m_id2;
}
В программе в какойто момент времени становится известно, сколько точек (скажем n1 и сколько связей (скажем n2 надо перегнать из одного процесса в другой.
Память я выделил размера n1*sizeof(node)+n2*sizeof(node_connection а копировать пытался типо так:
node * p_n;
node_connection * p_nc;
p_n=(node *)pointer;
p_nc=(node *pointer+n1*sizeof(node;
for (i=0; i<n1; i++)
{
p_n[i]=...
}
for (i=0; i<n2; i++)
{
p_nc[i]=...
}
Вобщем, понятно что в итоге не получилось
Решил, что пока буду гонять union из node и node_connection. Жаль только что придется памяти много лишней использовать, т.к. размер node больше размера node_connection, а связей обычно гораздо больше в системе.
Всем спасибо Главное понял, что простого пути нет
struct
{
int kind;
void *data;
};
а по kind уже решать - кастить data в node или node_connection ?
я бы даже инкапсулировал в большую структуру:
struct data
{
int nodes_cnt;
struct node * nodes;
int conn_cnt;
struct node_connections * conns;
};
Автору: А причём здесь С++ ?!
{
int kind;
void *data;
};
Чтото я не понял, что именно гонять по разделяемой памяти.
Указатели на объекты гонять нельзя, т.к. в принимающем процессе совсем своя область памяти, и что там по этим указателям будет лежать неизвестно
А С++ потому что в С++ программу пишу . Я бы конечно и рад, знать глобальный ответ для всех архитектур и языков программирования, но интересовали конкретные идеи для решения конкретной задачки, на конкретном языке программирования.
тогда так - выделяй памяти на 4+n1+4+n2
в места по 4 байта записывай размеры, на n1 и n2 - соответствующие данные.
в начале кусочка для правильности можешь записывать offset на вторые данные
2 : куда удалил, я ответить не успел?я написал примерно тоже что и аффтар, так что подумав я понял что не догоняю где тут косяк.
косяки только с выравниванием структур в массивах, и тут я понял что ничего про это не зняю.
структуры дополняются для сохранения выравнивания в массивах или нет?
почитал — дополняются.
тогда не вижу косяков у аффтара.
кроме того что лучше написать:
p_n=(struct node *)pointer;
p_nc=(struct node_connection *p_n+n1);
так ты через shmem гоняешь? сразу бы написал.Да, через shmem. Собственно изначально и интересовало, как получить offset на вторые данные.
тогда так - выделяй памяти на 4+n1+4+n2
в места по 4 байта записывай размеры, на n1 и n2 - соответствующие данные.
в начале кусочка для правильности можешь записывать offset на вторые данные
То есть Вы предлагаете так:
void * shmen_pointer;
shmen_pointer=MapViewOfFile(...);
long * g;
node * g2;
g=(long *)shmem_pointer;
*g=n1;
g2= ? //(node*shmem_pointer+sizeof(long
for (i=0; i<n1; i++)
{
g2[i]=node[i];
}
вот собственно инетерусет, что тут надо писать,где ? (long*shmem_pointer+sizeof(long так не работает, ибо shmem_pointer Имеет тип void*, а для него не определена операция суммирования Плюс, изза проблем с выравниванием есть мнение, что возможно так делать даже не корректно.
Далее,
зы. Кстати размеры n1,n2 второй процесс знает, они ему передаются через другую разделяемую память заранее.
в общем, я ответил выше =)
можно сделать так.
Предполагается, что блок target будет передаваться по разделяемой памяти и он достаточного размера, чтобы вместить оба массива.
void PrepareToSend(int n, node * nodes, int c, node_connections *cons, void * target)
{
int *p;
p=(int*)target;
p[0]=n;
p[1]=c;
p[2]=2*sizeof(int)+n*sizeof(node); // оффсет на второй массив
memcpy(p+3,nodes, n*sizeof(node;
memcpy(p+3+p[2],cons,c*sizeof(node_connections;
}
// принимающая сторона соответственно:
void Receive(void *target, int *n, node**nodes, int *c, node_connections **cons)
{
int *p;
p=(int*)target;
*n=p[0];
*c=p[1];
*nodes=malloc(*n*sizeof;
*cons=malloc(*c*sizeof;
memcpy(*nodes, p+3, ...)
memcpy(*cons, p+3+p[2], ...
}
Ок, спасибо попробую
советую посмотреть boost::any, может поможет...
p_long=(long*)VMDISP_pMapping;
p_long[0]=molecule->m_atoms_number;
p_long[1]=molecule->m_connections_number;
p_memcopy=(memcopy_atom*&p_long[2]);
p_connection=(vmdisp_connection*void*)&p_memcopy[molecule->m_atoms_number];
long i;
for (i=0; i<molecule->m_atoms_number; i++)
{
p_memcopy[i].x=molecule->m_atom_coordinates[i].x;
p_memcopy[i].y=molecule->m_atom_coordinates[i].y;
p_memcopy[i].z=molecule->m_atom_coordinates[i].z;
p_memcopy[i].m_vdw_radius=molecule->m_atoms[i].m_vdw_radius;
p_memcopy[i].m_color_r=molecule->m_atoms[i].m_color_r;
p_memcopy[i].m_color_g=molecule->m_atoms[i].m_color_g;
p_memcopy[i].m_color_b=molecule->m_atoms[i].m_color_b;
}
for (i=0; i<molecule->m_connections_number; i++)
{
p_connection[i].m_atom_n1=molecule->m_atom_connections[i].m_atom_n1;
p_connection[i].m_atom_n2=molecule->m_atom_connections[i].m_atom_n2;
}
Ну как?
Скоро проверю, правильно ли работает это дело
Заверни в XML, и передавай строчку Щас так модно
p_long=(long *pMapping+sizeof(float;А если написать что-нибудь вроде
p_long = (long *void *float *)pMapping ) + 1 ;
?
правильно делать через boost::shmem, удачи
Если структурой нельзя из-за того, что порядок и количество даных не известно во время компиляции, то надо сначала приводить указатель к типу (void* потом прибавлять смещение, а потом уже приводить к нужному типу. Но тут возможны проблемы с выравниванием и надо быть очень аккуратным.К типу void* нельзя применять арифметические операции, т.ч. смещение к нему прибавить невозможно.
в C++ да, а в C он как char*
распространение заведомо неверной информации
6.2.5 Types
...
26 A pointer to void shall have the same representation and alignment requirements as a
pointer to a character type. 39) Similarly, pointers to qualified or unqualified versions of
compatible types shall have the same representation and alignment requirements. All
pointers to structure types shall have the same representation and alignment requirements
as each other. All pointers to union types shall have the same representation and
alignment requirements as each other. Pointers to other types need not have the same
representation or alignment requirements.
39) The same representation and alignment requirements are meant to imply interchangeability as
arguments to functions, return values from functions, and members of unions.
арифметические действия с void * запрещены
int main {
void *a = NULL;
void *b = a+10;
int x = b-a;
printf("%p %p %d\n", a, b, x);
return 0;
}
c -Wall компилируются молча
и выводит (nil) 0xa 10
-pedantic юзай
работает усё, нах*й педантов.
Open Watcom C/C++ CL Clone for 386 Version 1.5
Portions Copyright (c) 1995-2006 Sybase, Inc. All Rights Reserved.
Source code is available under the Sybase Open Watcom Public License.
See http://www.openwatcom.org/ for details.
a.c
a.c(4): Error! E1066: Cannot perform operation with pointer to void
a.c(5): Error! E1066: Cannot perform operation with pointer to void
Так делать нельзя т.к. если вычитаешь из одного указателя другой они должны указывать на элементы одного массива или вымошленный последний символ этого массива
это С дружок =)
C Standart - 1999 Final draft
6.5.6 Additive operators
...
9 When two pointers are subtracted, both shall point to elements of the same array object,
or one past the last element of the array object; the result is the difference of the
subscripts of the two array elements.
это требование невозможно проверить во время компиляции, а в рантайме это уж точно никто делать не будет.
это требование к программисту, мол если это не так — то хз что там получится, сам виноват.
так что не "так делать нельзя" а "так лучше не делать"
> в места по 4 байта записывай размеры, на n1 и n2 - соответствующие данные.
Не надо так делать.
Правильнее size_t+size_t+n1*sz1+n2*sz2, где sz[12] ---
размеры структур, добитых до принятого выравнивания.
Или вообще использовать не количества, а смещения
в адресуемых единицах.
Только тогда надо смотреть на архитектуру.
---
...Я работаю антинаучным аферистом...
Оставить комментарий
vertyal17
Например по адресу pMapping поместить float, long и unsigned char;Казалось логичным сделать чтото в духе такого:
char * p_uchar;
float * p_float;
long * p_long;
p_float=(float*pMapping);
p_long=(long *pMapping+sizeof(float;
p_uchar=(unsigned char *pMapping + sizeof(float)+sizeof(long
Но не работает. Как принято делать правильно?