Message queue msgsnd mtext field - linux

When using msgsnd the structure mentioned in man page is
struct mymsg {
long mtype; /* message type */
char mtext[1]; /* body of message */
};
But if you use it like
func(char *array, int sizeofarray)
{
struct mymsg {
long mtype; /* message type */
char *ptr; /* body of message */
};
msgq.mtype = 1;
msgq.ptr = array;
msgsnd(msqid, &msgq, sizeofarray, 0);
}
Assign ptr to some local array[200] (array could be got as a parameter in function), the message received on the other side is junk. Why is this?

It's junk because the structure you have specified is not of the form that msgsnd wants. It expects the data to be copied to immediately follow the mtype value in memory, not be in an array somewhere else.
If you want to send an array of length 200, you need to do something like:
struct mymsg {
long mtype;
char mtext[200];
} foo;
foo.mtype = 1;
memcpy(foo.mtext, array, 200);
msgsnd(msqid, &foo, 200, 0);

Even if this wasn't wrong for the reasons caf points out, let's say you did something like:
func(char *array)
{
struct mymsg
{
long mtype; /* message type */
char *ptr; /* body of message */
};
msgq.mtype = 1;
msgq.ptr = array;
msgsnd(msqid, &msgq, sizeof(ptr), 0);
}
If a different process is reading the queue, what would ptr mean to it? What would it point to, if anything, in a different address space?

Related

Creating dynamically sized MPI file views

I would like to write out a binary file using collective MPI I/O. My plan is to create an MPI derived type analogous to
struct soln_dynamic_t
{
int int_data[2];
double *u; /* Length constant for all instances of this struct */
};
Each processor then creates a view based on the derived type, and writes into the view.
I have this all working for the case in which *u is replaced with u[10] (see complete code below), but ultimately, I'd like to have a dynamic length array for u. (In case it matters, the length will be fixed for all instances of soln_dynamic_t for any run, but not known at compile time.)
What is the best way to handle this?
I have read several posts on why I can't use soln_dynamic_t
directly as an MPI structure. The problem is that processors are not guaranteed to have the same offset between u[0] and int_data[0]. (Is that right?)
On the other hand, the structure
struct soln_static_t
{
int int_data[2];
double u[10]; /* fixed at compile time */
};
works because the offsets are guaranteed to be the same across processors.
I've considered several approaches :
Create the view based on manually defined offsets, etc, rather than using a derived type.
Base the MPI structure on another MPI type, i.e. an contiguous type for ``*u` (is that allowed?)
I am guessing there must be a standard way to do this. Any suggestions would be very helpful.
Several other posts on this issue have been helpful, although they mostly deal with communication and not file I/O.
Here is the complete code::
#include <mpi.h>
typedef struct
{
int int_data[2];
double u[10]; /* Make this a dynamic length (but fixed) */
} soln_static_t;
void build_soln_type(int n, int* int_data, double *u, MPI_Datatype *soln_t)
{
int block_lengths[2] = {2,n};
MPI_Datatype typelist[2] = {MPI_INT, MPI_DOUBLE};
MPI_Aint disp[2], start_address, address;
MPI_Address(int_data,&start_address);
MPI_Address(u,&address);
disp[0] = 0;
disp[1] = address-start_address;
MPI_Datatype tmp_type;
MPI_Type_create_struct(2,block_lengths,disp,typelist,&tmp_type);
MPI_Aint extent;
extent = block_lengths[0]*sizeof(int) + block_lengths[1]*sizeof(double);
MPI_Type_create_resized(tmp_type, 0, extent, soln_t);
MPI_Type_commit(soln_t);
}
void main(int argc, char** argv)
{
MPI_File file;
int globalsize, localsize, starts, order;
MPI_Datatype localarray, soln_t;
int rank, nprocs, nsize = 10; /* must match size in struct above */
/* --- Initialize MPI */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
/* --- Set up data to write out */
soln_static_t data;
data.int_data[0] = nsize;
data.int_data[1] = rank;
data.u[0] = 3.14159; /* To check that data is written as expected */
build_soln_type(nsize, data.int_data, data.u, &soln_t);
MPI_File_open(MPI_COMM_WORLD, "bin.out",
MPI_MODE_CREATE|MPI_MODE_WRONLY,
MPI_INFO_NULL, &file);
/* --- Create file view for this processor */
globalsize = nprocs;
localsize = 1;
starts = rank;
order = MPI_ORDER_C;
MPI_Type_create_subarray(1, &globalsize, &localsize, &starts, order,
soln_t, &localarray);
MPI_Type_commit(&localarray);
MPI_File_set_view(file, 0, soln_t, localarray,
"native", MPI_INFO_NULL);
/* --- Write data into view */
MPI_File_write_all(file, data.int_data, 1, soln_t, MPI_STATUS_IGNORE);
/* --- Clean up */
MPI_File_close(&file);
MPI_Type_free(&localarray);
MPI_Type_free(&soln_t);
MPI_Finalize();
}
Since the size of the u array of the soln_dynamic_t type is known at runtime and will not change after that, I'd rather suggest an other approach.
Basically, you store all the data contiguous in memory :
typedef struct
{
int int_data[2];
double u[]; /* Make this a dynamic length (but fixed) */
} soln_dynamic_t;
Then you have to manually allocate this struct
soln_dynamic_t * alloc_soln(int nsize, int count) {
return (soln_dynamic_t *)calloc(offsetof(soln_dynamic_t, u)+nsize*sizeof(double), count);
}
Note you cannot directly access an array of soln_dynamic_t because the size is unknown at compile time. Instead, you have to manually calculate the pointers.
soln_dynamic_t *p = alloc_soln(10, 2);
p[0].int_data[0] = 1; // OK
p[0].u[0] = 2; // OK
p[1].int_data[0] = 3; // KO ! since sizeof(soln_dynamic_t) is unknown at compile time.
Here is the full rewritten version of your program
#include <mpi.h>
#include <malloc.h>
typedef struct
{
int int_data[2];
double u[]; /* Make this a dynamic length (but fixed) */
} soln_dynamic_t;
void build_soln_type(int n, MPI_Datatype *soln_t)
{
int block_lengths[2] = {2,n};
MPI_Datatype typelist[2] = {MPI_INT, MPI_DOUBLE};
MPI_Aint disp[2];
disp[0] = offsetof(soln_dynamic_t, int_data);
disp[1] = offsetof(soln_dynamic_t, u);
MPI_Datatype tmp_type;
MPI_Type_create_struct(2,block_lengths,disp,typelist,&tmp_type);
MPI_Aint extent;
extent = offsetof(soln_dynamic_t, u) + block_lengths[1]*sizeof(double);
MPI_Type_create_resized(tmp_type, 0, extent, soln_t);
MPI_Type_free(&tmp_type);
MPI_Type_commit(soln_t);
}
soln_dynamic_t * alloc_soln(int nsize, int count) {
return (soln_dynamic_t *)calloc(offsetof(soln_dynamic_t, u) + nsize*sizeof(double), count);
}
int main(int argc, char** argv)
{
MPI_File file;
int globalsize, localsize, starts, order;
MPI_Datatype localarray, soln_t;
int rank, nprocs, nsize = 10; /* must match size in struct above */
/* --- Initialize MPI */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nprocs);
/* --- Set up data to write out */
soln_dynamic_t *data = alloc_soln(nsize,1);
data->int_data[0] = nsize;
data->int_data[1] = rank;
data->u[0] = 3.14159; /* To check that data is written as expected */
build_soln_type(nsize, &soln_t);
MPI_File_open(MPI_COMM_WORLD, "bin2.out",
MPI_MODE_CREATE|MPI_MODE_WRONLY,
MPI_INFO_NULL, &file);
/* --- Create file view for this processor */
globalsize = nprocs;
localsize = 1;
starts = rank;
order = MPI_ORDER_C;
MPI_Type_create_subarray(1, &globalsize, &localsize, &starts, order,
soln_t, &localarray);
MPI_Type_commit(&localarray);
MPI_File_set_view(file, 0, soln_t, localarray,
"native", MPI_INFO_NULL);
/* --- Write data into view */
MPI_File_write_all(file, data, 1, soln_t, MPI_STATUS_IGNORE);
/* --- Clean up */
MPI_File_close(&file);
MPI_Type_free(&localarray);
MPI_Type_free(&soln_t);
MPI_Finalize();
return 0;
}

how to implement splice_read for a character device file with uncached DMA buffer

I have a character device driver. It includes a 4MB coherent DMA buffer. The buffer is implemented as a ring buffer. I also implemente the splice_read call for the driver to improve the performance. But this implementation does not work well. Below is the using example:
(1)splice the 16 pages of device buffer data to a pipefd[1]. (the DMA buffer is managed as in page unit).
(2)splice the pipefd[0] to the socket.
(3)the receiving side (tcp client) receives the data, and then check the correctness.
I found that the tcp client got errors. The splice_read implementation is show below (I steal it from the vmsplice implementation):
/* splice related functions */
static void rdma_ring_pipe_buf_release(struct pipe_inode_info *pipe,
struct pipe_buffer *buf)
{
put_page(buf->page);
buf->flags &= ~PIPE_BUF_FLAG_LRU;
}
void rdma_ring_spd_release_page(struct splice_pipe_desc *spd, unsigned int i)
{
put_page(spd->pages[i]);
}
static const struct pipe_buf_operations rdma_ring_page_pipe_buf_ops = {
.can_merge = 0,
.map = generic_pipe_buf_map,
.unmap = generic_pipe_buf_unmap,
.confirm = generic_pipe_buf_confirm,
.release = rdma_ring_pipe_buf_release,
.steal = generic_pipe_buf_steal,
.get = generic_pipe_buf_get,
};
/* in order to simplify the caller work, the parameter meanings of ppos, len
* has been changed to adapt the internal ring buffer of the driver. The ppos
* indicate wich page is refferred(shoud start from 1, as the csr page are
* not allowed to do the splice), The len indicate how many pages are needed.
* Also, we constrain that maximum page number for each splice shoud not
* exceed 16 pages, if else, a EINVAL will return. If a high speed device
* need a more big page number, it can rework this routing. The off is also
* used to return the total bytes shoud be transferred, use can compare it
* with the return value to determint whether all bytes has been transfered.
*/
static ssize_t do_rdma_ring_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len,
unsigned int flags)
{
struct rdma_ring *priv = to_rdma_ring(in->private_data);
struct rdma_ring_buf *data_buf;
struct rdma_ring_dstatus *dsta_buf;
struct page *pages[PIPE_DEF_BUFFERS];
struct partial_page partial[PIPE_DEF_BUFFERS];
ssize_t total_sz = 0, error;
int i;
unsigned offset;
struct splice_pipe_desc spd = {
.pages = pages,
.partial = partial,
.nr_pages_max = PIPE_DEF_BUFFERS,
.flags = flags,
.ops = &rdma_ring_page_pipe_buf_ops,
.spd_release = rdma_ring_spd_release_page,
};
/* init the spd, currently we omit the packet header, if a control
* is needed, it may be implemented by define a control variable in
* the device struct */
spd.nr_pages = len;
for (i = 0; i < len; i++) {
offset = (unsigned)(*ppos) + i;
data_buf = get_buf(priv, offset);
dsta_buf = get_dsta_buf(priv, offset);
pages[i] = virt_to_page(data_buf);
get_page(pages[i]);
partial[i].offset = 0;
partial[i].len = dsta_buf->bytes_xferred;
total_sz += partial[i].len;
}
error = _splice_to_pipe(pipe, &spd);
/* use the ppos to return the theory total bytes shoud transfer */
*ppos = total_sz;
return error;
}
/* splice read */
static ssize_t rdma_ring_splice_read(struct file *in, loff_t *ppos,
struct pipe_inode_info *pipe, size_t len, unsigned int flags)
{
ssize_t ret;
MY_PRINT("%s: *ppos = %lld, len = %ld\n", __func__, *ppos, (long)len);
if (unlikely(len > PIPE_DEF_BUFFERS))
return -EINVAL;
ret = do_rdma_ring_splice_read(in, ppos, pipe, len, flags);
return ret;
}
The _splice_to_pipe is just the same one as the splice_to_pipe in kernel. As this function is not an exported symbol, so I re-implemented it.
I think the main cause is that the some kind of lock of pages are omitted, but
I don't know where and how.
My kernel version is 3.10.

Change read_proc_t read_proc and write_proc_t write_proc of an existing file in /proc

I'm actually working lkm on linux 2.6.32, and I don't to understand one thing. I'm trying to change the original read_proc and write_proc of /proc/version with my functions. Thus I can to change the original value of read_proc and write_proc, with values of my function. I can see it, because values of read_proc and write_proc change to NULL to adress of my functions, but that have no effect... And I don't understand why. I don't arrive to find if version is protected (I tried to change the value of file's right with chmod), or why even after change the value, I can't write in /proc/version with echo XXXX > /proc/version. I'll be grateful for your help.
Code where I try to change values of read_proc and write_proc:
static void Proc_init()
{
int find = 0;
pde = create_proc_entry("test", 0444, NULL); //that permit to create new file in /proc, only to get some useful values
ptdir = pde->parent; //affect to ptdir the value of the pointer on /proc
if(strcmp(ptdir->name, "/proc")!=0)
{
Erreur=1;
}
else
{
root = ptdir;
remove_proc_entry("test", NULL);
ptr_subdir=root->subdir;
while(find==0)
{
printk("%s \n", ptr_subdir->name);
if(strcmp("version", ptr_subdir->name)==0)
find=1;
else
ptr_subdir=ptr_subdir->next;
}
//Save original write et read proc
old_read_proc=ptr_subdir->read_proc;
old_write_proc=ptr_subdir->write_proc;
// Before I have null values for prt_subdir->read_proc and ptr_subdir->write_proc
ptr_subdir->read_proc=&new_read_proc_t;
ptr_subdir->write_proc=&new_write_proc_t;
// after that, values of prt_subdir->read_proc and ptr_subdir- >write_proc are egual to values of &new_write_proc_t and &new_read_proc_t
}
}
static int new_read_proc_t (char *page, char **start, off_t off,int count, int *eof, void *data)
{
int len;
/* For example - when content of our_buf is "hello" - when user executes command "cat /proc/test_proc"
he will see content of our_buf(in our example "hello" */
len = snprintf(page, count, "%s", our_buf);
return len;
}
static int new_write_proc_t(struct file *file, const char __user *buf,unsigned long count, void *data)
{
/* If count is bigger than 255, data which user wants to write is too big to fit in our_buf. We don't want
any buffer overflows, so we read only 255 bytes */
if(count > 255)
count = 255;
/* Here we read from buf to our_buf */
copy_from_user(our_buf, buf, count);
/* we write NULL to end the string */
our_buf[count] = '\0';
return count;
}

Multhreaded programming in C

I have been given an assignment. There is a dictionary of 25 files and each file has random text involving random IP addresses. The task is to find out and output the count of unique IP addresses among all files using the pthread library in C.
I think I have solved the race condition on count variable by mutual exclusion. But, still there is a bug and the code has different count value in each execution.
Here is the code, please suggest fixes for the bug:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <pthread.h>
#include <string.h>
//declaring structure of arguments to give arguments to thread function
struct arg_struct
{
char *arg1; //argument 1 : to pass directory name to thread function
struct dirent *arg2; //argument 2: to pass file name to thread function
};
//declaring structure of pointer which will point unique ip addresses
struct uniqueip
{
char *ip;
};
struct filenames
{
char full_filename[256];
};
struct uniqueip u[200];
int count=0;// global count variable stores total unique ip addresses.
void *ReadFile(void *thread_no);//thread declaration
pthread_mutex_t mutex;
int main(int argc, char *argv[])
{
DIR *dir; //directory stream
FILE *file; //file stream
struct dirent *ent; // directory entry structure
char *line = NULL; // pointer to
size_t len = 1000; //the length of bytes getline will allocate
size_t read;
char full_filename[256]; //will hold the entire file path with
//file name to read
int x=0;
pthread_attr_t attr;
int rc;
long thread_no;
void *status;
void *ReadFile(void *thread_no);
// check the arguments
if(argc < 2)
{
printf("Not enough arguments supplied\n");
return -1;
}
if(argc > 2)
{
printf("Too many arguments supplied\n");
return -1;
}
struct arg_struct args;
args.arg1 = argv[1];
pthread_mutex_init(&mutex, NULL); // initializing mutex
/* Initialize and set thread detached attribute */
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
// try to open the directory given by the argument
if ((dir = opendir (argv[1])) != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL)
{
// Check if the list is a regular file
if(ent->d_type == DT_REG)
{
//Get the number of files first so that we would know number
//of threads to be created
x++;
}
}
}
pthread_t thread[x];
struct filenames filenames[x];
thread_no=0;
// try to open the directory given by the argument
if ((dir = opendir (argv[1])) != NULL)
{
/* print all the files and directories within directory */
while ((ent = readdir (dir)) != NULL)
{
// Check if the list is a regular file
if(ent->d_type == DT_REG)
{
// Create the absolute path of the filename
snprintf(filenames[thread_no].full_filename, sizeof filenames[thread_no].full_filename,
"./%s/%s", argv[1], ent->d_name);
//creating threads to read files
args.arg2 = ent; //assigning file name to argument 2
printf("main: creating thread %ld %s \n", thread_no,ent->d_name);
rc = pthread_create(&thread[thread_no], &attr, ReadFile, (void *) &args);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
thread_no++;
}
}
// Close the directory structure
closedir (dir);
}
else
{
/* could not open directory */
perror ("");
return -1;
}
/* Free attribute and wait for the other threads*/
pthread_attr_destroy(&attr);
for(thread_no=0; thread_no<x; thread_no++)
{
rc = pthread_join(thread[thread_no], &status);
if (rc)
{
printf("ERROR; return code from pthread_join() is %d\n", rc);
exit(-1);
}
printf("Main: completed join with thread %ld having a status of %ld\n",thread_no,(long)status);
}
printf("Main: program completed. Exiting.\n");
printf("total no. of unique ip addresses are %d\n",count-1);
pthread_mutex_destroy(&mutex);
pthread_exit(NULL);
return 0;
}
void *ReadFile(void *thread_no)
{ // in thread function
struct filenames *my_data;
my_data = (struct filenames *)thread_no;
char full_filename[256];
FILE *file; //file stream
char *line = NULL;
char *split = NULL;
size_t len = 1000; // pointer to the length of bytes getline will allocate
size_t read;
const char s[2]=" "; //used as string split to get ip address
char *token;
int flag = 0,j;
// open the file
file = fopen(my_data -> full_filename, "r");
// file was not able to be open
if (file != NULL)
{
// Print out each line in the file
while ((read = getline(&line, &len, file)) != -1)
{
split=line;
token = strtok(split,s);
pthread_mutex_lock(&mutex);
if(count==0){
//locking mutex variable to avoid race condition
u[count].ip=malloc(sizeof(token)+1);
strcpy(u[count].ip,token);
printf("%d ------ %s\n",count,u[count].ip);
free(u[count].ip);
count++;
}
pthread_mutex_unlock(&mutex); // unlocking mutex
//comparing recently received ip address to all the stored unique ip address.
for(j=0;j<count;j++)
{
if(!(strcmp(u[j].ip,token)))
{
break;
}
else
{
if(j==count-1){
pthread_mutex_lock(&mutex); //locking mutex variable to avoid race condition
u[count].ip=malloc(sizeof(read));
strcpy(u[count].ip,token);
printf("%d ------ %s\n",count,u[count].ip);
count++;
free(u[count].ip);
pthread_mutex_unlock(&mutex); // unlocking mutex
}
}
}
}
}
fclose(file);
pthread_exit((void*) thread_no);
}
There's several issues in this code.
You only ever create one instance of arg_struct, but you re-use it and pass it to every thread. This means that by the time a thread starts, the value of the arg_struct you passed it may have changed. You need to give each thread its own arg_struct - eg. you could declare an array of them alongside the pthread_t array:
pthread_t thread[x];
struct arg_struct args[x];
A similar problem exists with the struct dirent * pointer inside arg_struct - the data pointed to by the struct dirent * returned by readdir() may be overwritten by the next call to readdir() on the same directory stream. There are a few ways to solve this, but one way is to replace the char *arg1; and struct dirent * in arg_struct with a buffer to hold the filename:
struct arg_struct
{
char full_filename[256]; //will hold the entire file path with
//file name to read
};
The main thread can then be changed to put the filename straight into the arg_struct:
snprintf(args[thread_no].full_filename, sizeof args[thread_no].full_filename, "./%s/%s", argv[1], ent->d_name);
In the ReadFile() function, this creates an array of one element and then tries to write to the (non-existent) second element, which has undefined behaviour:
char * argv[1];
argv[1]= my_data->arg1;
That code can be removed entirely, though - now that main() is constructing the full filename for the thread, the thread can just directly open it from the the arg_struct:
file = fopen(my_data->full_filename, "r");
(The thread doesn't need to worry about argv[1] at all anymore).
Your thread function is reading the shared count variable without holding the mutex - you need to lock the mutex before executing if (count == 0), and don't unlock it until after the for () loop (otherwise, you might get two threads deciding to add an IP to the same array location).
When you try to create a copy of the string you want to store, you aren't allocating enough space: sizeof read is always the fixed size of a size_t variable and isn't related to the size of the string you're copying. You want:
u[count].ip = malloc(strlen(token) + 1);
strcpy(u[count].ip, token);
You don't want to immediately free the u[count].ip, either: you need that string to stay allocated. Remove the free(u[count].ip); lines.
There's some easy optimisations you could make, once you get it working. For example, because count only increases and the u[] array is static below the value of count, you can lock the mutex, save a copy of count then unlock the mutex. Loop up to the saved value of count - if you find the string then you can just move straight onto the next line of your input file. It's only if you don't find the string that you need to re-lock the mutex, then continue from the saved count value up to the current count value (which might have increased in the meantime), adding the new string to the array (and incrementing count) if nececssary.

Initial assignment a Char Array using a Function in C

as we know it in C, a string defining is,
char string[] = "Hello World";
That is OK,
But I want to use a function and at initial same up,
I tried those, For example;
char * to_string()
{
return "Hello World";
}
Or;
char * to_String(void) // Function
{
char buff[16];
sprintf(buff, "%s", "Hello World");
return buff;
}
main() // main function
{
char Initial_String[] = to_String();
}
How to make this or any idea same another way.
I find what I dont send address of char Initial_String[] to fill into. No. is there Another method.
Thanks.
When you compile this, atleast in GCC, it will give you the following warning:
b.c:9: warning: function returns address of local variable
Why? Because buff[] is a local variable of function to_string(). Its scope is only inside the function to_string(). main() does not have any access to this variable. Try making buff[] a global variable instead.
Second problem: char Initial_String[] = to_String(); cannot be assigned value in this way. to_string() returns a char pointer, hence assign the value thus:
char *Initial_String = to_String();
The code below will work:
char buff[16];
char* to_String(void) // Function
{
//char buff[16]; /*this is a local variable*/
sprintf(buff, "%s", "Hello World");
return buff;
}
int main(void) // main function
{
char *Initial_String = to_String();
printf("%s", Initial_String);
return 0;
}
Yes You are right about local buffer mismake,
But This is not my wanting,
if I edit some differently,
char buff[16];
char* to_String(void) // Function
{
//char buff[16]; /*this is a local variable*/
sprintf(buff, "%s", "Hello World");
return buff;
}
int main(void) // main function
{
char *Initial_String_1 = to_String();
char *Initial_String_2 = to_String();
char *Initial_String_3 = to_String();
printf("%s", Initial_String_1 );
printf("%s", Initial_String_2 );
printf("%s", Initial_String_3 );
in this case, all strings will be same, because They have same buffer address,
I want to open the topic little more.
struct
{
long aaa;
short bbb;
int ccc;
char ddd;
.
.
. // the list goes on
}elements;
typedef struct
{
int lengt;
int *adress;
char name[10];
}_list;
char* to_String(long variable) // Function
{
sprintf(buff, "%ld", variable);
return buff;
}
int main (void)
{
_list My_List[] = {
{ sizeof(elements.aaa), &elements.aaa , to_string( elements.aaa) },
{ sizeof(elements.bbb), &elements.bbb , to_string( elements.bbb) },
{ sizeof(elements.ccc), &elements.ccc , to_string( elements.ddd) },
.
.
. //// the list goes on
};
I do not know, Do I make myself clear.
Here, string must be filled into name array, without assigning it the address.
I may have syntax mistake. the code is not tested with compiler. the idea is for illustrative purposes only.
I am trying to find a method for The purpose.
Thanks.

Resources