C++, по указателю разместить в памяти разнотипные данные

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
Но не работает. Как принято делать правильно?

otets-mihail

структурой

sbs-66

Если структурой нельзя из-за того, что порядок и количество даных не известно во время компиляции, то надо сначала приводить указатель к типу (void* потом прибавлять смещение, а потом уже приводить к нужному типу. Но тут возможны проблемы с выравниванием и надо быть очень аккуратным.

psm-home

ыыыы, я был невнимателен.

Realist

Мб union спасет отца русской демократии? А вообще просто не надо так писать и все. Если надо, могу не поленится привести ссылку на (бумажную) книгу Герба Саттера, где этот вопрос подробно разбирается.

yolki

+1 за union или struct.

vall

можно попробовать структурой с атрибутом packed, но хз как оно себя поведёт на системах с обязательным выравниванием.
самба использует свои извратные макросы, лежат в byteorder.h
а откуда могут свалится флоаты в блоке? их вроде-как не принято по сети гонять в таком виде.

vertyal17

их вроде-как не принято по сети гонять в таком виде.
\
По сети и не гоняю, это на одной машине делается.
А вообще до 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, а связей обычно гораздо больше в системе.
Всем спасибо Главное понял, что простого пути нет

yolki

может, стоит гонять
struct
{
int kind;
void *data;
};
а по kind уже решать - кастить data в node или node_connection ?

yolki

2 : куда удалил, я ответить не успел?
я бы даже инкапсулировал в большую структуру:

struct data
{
int nodes_cnt;
struct node * nodes;
int conn_cnt;
struct node_connections * conns;
};

Автору: А причём здесь С++ ?!

vertyal17

struct
{
 int kind;
 void *data;
};
Чтото я не понял, что именно гонять по разделяемой памяти.
Указатели на объекты гонять нельзя, т.к. в принимающем процессе совсем своя область памяти, и что там по этим указателям будет лежать неизвестно
А С++ потому что в С++ программу пишу . Я бы конечно и рад, знать глобальный ответ для всех архитектур и языков программирования, но интересовали конкретные идеи для решения конкретной задачки, на конкретном языке программирования.

yolki

так ты через shmem гоняешь? сразу бы написал.
тогда так - выделяй памяти на 4+n1+4+n2
в места по 4 байта записывай размеры, на n1 и n2 - соответствующие данные.
в начале кусочка для правильности можешь записывать offset на вторые данные

vall

2 : куда удалил, я ответить не успел?
я написал примерно тоже что и аффтар, так что подумав я понял что не догоняю где тут косяк.
косяки только с выравниванием структур в массивах, и тут я понял что ничего про это не зняю.
структуры дополняются для сохранения выравнивания в массивах или нет?
почитал — дополняются.
тогда не вижу косяков у аффтара.
кроме того что лучше написать:
p_n=(struct node *)pointer;
p_nc=(struct node_connection *p_n+n1);

vertyal17

так ты через shmem гоняешь? сразу бы написал.
тогда так - выделяй памяти на 4+n1+4+n2
в места по 4 байта записывай размеры, на n1 и n2 - соответствующие данные.
в начале кусочка для правильности можешь записывать offset на вторые данные
Да, через shmem. Собственно изначально и интересовало, как получить 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 второй процесс знает, они ему передаются через другую разделяемую память заранее.

vall

в общем, я ответил выше =)

yolki

проблема в том, что автору требуется как-нить обойтись без указателей.
можно сделать так.
Предполагается, что блок 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], ...
}

vertyal17

Blind,
Ок, спасибо попробую

okunek

немножко оффтоп
советую посмотреть boost::any, может поможет...

vertyal17

Во как сделал, компилирует
 
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;
}

Ну как?
Скоро проверю, правильно ли работает это дело

smit1

>Чтото я не понял, что именно гонять по разделяемой памяти.
Заверни в XML, и передавай строчку Щас так модно

apl13

p_long=(long *pMapping+sizeof(float;
А если написать что-нибудь вроде
p_long = (long *void *float *)pMapping ) + 1 ;
?

buka

правильно делать через boost::shmem, удачи

erotic

Если структурой нельзя из-за того, что порядок и количество даных не известно во время компиляции, то надо сначала приводить указатель к типу (void* потом прибавлять смещение, а потом уже приводить к нужному типу. Но тут возможны проблемы с выравниванием и надо быть очень аккуратным.
К типу void* нельзя применять арифметические операции, т.ч. смещение к нему прибавить невозможно.

vall

в C++ да, а в C он как char*

yolki

распространение заведомо неверной информации

vall

в плане адресной арифметики он такой-же.
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.

yolki

то, что ты процитировал касается представления [как целого числа] и выравнивания в структурах.
арифметические действия с void * запрещены

vall

#include <stdio.h>
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

otets-mihail

-pedantic юзай

vall

работает усё, нах*й педантов.

yolki

к слову, мой любимый компилятор:

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

Reves2

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

vall

это С дружок =)

Reves2


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.

vall

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

Ivan8209

> тогда так - выделяй памяти на 4+n1+4+n2
> в места по 4 байта записывай размеры, на n1 и n2 - соответствующие данные.
Не надо так делать.
Правильнее size_t+size_t+n1*sz1+n2*sz2, где sz[12] ---
размеры структур, добитых до принятого выравнивания.
Или вообще использовать не количества, а смещения
в адресуемых единицах.
Только тогда надо смотреть на архитектуру.
---
...Я работаю антинаучным аферистом...
Оставить комментарий
Имя или ник:
Комментарий: