简体   繁体   中英

C - Difficulties writing whole struct to Shared Memory

I'm having problems writing a structure to shared memory because when I do, the code only writes the first part of the structure.

Here's my data structure:

struct shmData{
    char number[4];
    char description[1020];
};

Here's my code:

//Structure Pointer - placed on SHM
struct shmstruct *ptr;
char description_to_write[1024] = {0};
struct shmData *data_ptr;
data_ptr = (struct shmData*) description_to_write;

//Shared Memory init
create_shm(&ptr);
printf("Started\n");

//Define Offsets
//init_shm(ptr);

//#########################

//Check if number exist
    if (!(strcmp("NO SUCH CODE\0", get_description(ptr, 6)))) {
        //-> If not, get next offset (nput) where to write new data
//      sem_wait(&ptr->mutex);
//      long offset = ptr->msgoff[ptr->nput];
//      printf("OFFSET: %li\n", offset);
//      if (++(ptr->nput) > NMESG)
//          ptr->nput = 0; /* circular buffer */
//      sem_post(&ptr->mutex);
//      printf("Buffer: %s", argv[2]);

    snprintf(data_ptr->number, 4, "%s", "6");
    snprintf(data_ptr->description, 1020, "%s\n", argv[2]);

    printf("DATA: %s\n", data_ptr->number);
    printf("DATA: %s\n", data_ptr->description);

    printf("description_to_write: %i\n", description_to_write);

    //strcpy(&ptr->msgdata[offset], );
    //sem_post(&ptr->nstored);
    //printf("Wrote...\n\n");
} else {
    //-> Else get offset of this number and put data to it
}

How should I write this? In the code above, I tried simply to display the description array but I only get the number back.

I need it to be written to shared memory as follows:

Number(space)(space)(space)Description

Shared Memory Dump looks like:

00003b0: 3120 2020 496e 7075 7420 4572 726f 720a  1   Input Error.
00003c0: 0000 0000 0000 0000 0000 0000 0000 0000  ................
*
00007b0: 3220 2020 4f75 7470 7574 2045 7272 6f72  2   Output Error
00007c0: 0a00 0000 0000 0000 0000 0000 0000 0000  ................
00007d0: 0000 0000 0000 0000 0000 0000 0000 0000  ................

From debugger:

description_to_write[0] char    54 '6'  
description_to_write[1] char    0 '\000'    
description_to_write[2] char    0 '\000'    
description_to_write[3] char    0 '\000'
description_to_write[4] char    83 'S'  
description_to_write[5] char    111 'o' 
description_to_write[6] char    109 'm' 
description_to_write[7] char    101 'e' 
description_to_write[8] char    84 'T'  
description_to_write[9] char    101 'e' 
description_to_write[10]char    120 'x' 
description_to_write[11]char    116 't' 
description_to_write[12]char    10 '\n' 

Ugly solution:

int i = 0;
        while(i < 4){
            if(data_ptr->number[i] == '\000'){
                data_ptr->number[i] = 32;
            }
            i++;
        }

The 4 passsed to snprintf specifies the MAXIMUM number of chars to write. Not the amount to write. snprtinf retursn the number of chars it did write. So you are only printing 1 char, which leaves 3 nulls after it.

Just do:

snprintf(data->number,4,"%s    ","6");

That way it will try and print the string followed by 4 spaces, and print a max of 4 charcacters.

Your ugly solution to use snprintf() and then rewrite '\\0' characters as spaces has some flaws:

  • snprintf() will never write a digit into data_ptr->number[3] . For strings longer than 3 characters it will truncate and write a '\\0' instead of copying the 4th character in the source string.

  • unless you're sure that the structure will be zero initialized before calling snprintf() then characters after the '\\0' that snprintf() is required to write will not be set to anything by snprintf() . That might not be a problem in your code as posted, but it's fragile in the face of changes to how the structure data_ptr points to is allocated and initialized.

Since the field is so small, you might consider something like:

memset( data_ptr->number, ' ', sizeof(data_ptr->number));
memcpy( data_ptr->number, "6", strlen("6"));

That still has a drawback that you need to add a bit more logic if the source string can possibly be longer than the field size. Also, if it's something that you'll be doing in more than one or two spots it can easily become a source of copy/paste bugs.

Here's a lightly tested function that you can use instead (though I'll admit that I hate the name):

size_t str2mem_padded( char* dest, size_t dest_size, char const* src, char fill)
{
    size_t result = 0;

    while (dest_size && *src) {
        *dest++ = *src++;
        ++result;
        --dest_size;
    }
    while (dest_size) {
        *dest++ = fill;
        --dest_size;
    }

    return result; // returns number of chars copied from src so you 
                   //   can determine if there was truncation
}

In your code, you might use the following instead of the call to snprintf(data_ptr->number, 4, "%s", "6") :

str2mem_padded( data_ptr->number, sizeof(data_ptr->number), "6", ' ');

Wow - that was a lot more effort than I thought it would be.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM