Initializing an array of structs into shared memor

2019-06-04 05:05发布

问题:

I'm making 4 programs that creates a POSIX shared memory object, an array of structs, that will be shared by the other 3 processes. Basically this project simulates files.

Program #1 creates the object. Program #2 takes a filename and a string as arguments, then the filename and string (file contents) are saved to shared memory as a struct that is put in an available element of the array. Program #3 will list the filenames. Program #4 will search for a given file and display its contents.

The trouble I'm having is initialize an array of structs into shared memory. I keep getting the following errors, which tells me I'm using an incorrect method initializing the pointers:

myformat.c:36: warning: initialization from incompatible pointer type

I've searched this subject and found a few similar problems, but nothing really relative to my issue.

So, how do you properly initializing an array of structs into shared memory?

Based on my research, I have coded the following. Thanks!

PROGRAM #1 (myformat.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>

struct MyFiles
{    
    char *fileName;    
    char *fileContents;    
};

int main()    
{    
    /* the size of shared memory object */    
    int size = sizeof(struct MyFiles)* 20;

    /* name of the shared memory object */    
    const char *name = "/PROJ4_SHARED_MEM";     

    /* shared memory file descriptor */    
    int shm_fd;

    /* pointer to shared memory obect */    
    void *ptr;

    /* create the shared memory object */    
    shm_fd = shm_open(name, O_CREAT | O_RDRW, 0666);    

    /* configure the size of the shared memory object */    
    ftruncate(shm_fd, size);    

    /* memory map the shared memory object */    
    ptr = mmap(0, size, PROT_WRITE, MAP_SHARED, shm_fd, 0);    
    struct MyFiles* file = (struct MyStruct*)ptr;           

    /* save struct array to the shared memory object. Initialize first element. */    
    file[0]->fileName = "\0";    
    file[0]->fileContents = "\0";       

    return 0;

}

PROGRAM #2 (mycreate.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>

struct MyFiles
{
    char *fileName;
    char *fileContents;
};

int main()
{
    char *file_name = argv(0);
    char *file_contents = argv(1);

    /* the size of shared memory object */
    int size = sizeof(struct MyFiles)* 20;

    /* name  of  the  shared  memory  object */
    const  char  *name = "/PROJ4_SHARED_MEM";

    /* shared  memory  file descriptor */
    int shm_fd;

    /* pointer to  shared  memory  object  */
    void  *ptr;

    /* open the  shared  memory  object */
    shm_fd = shm_open(name, O_RDRW, 0666);

    /* memory map the shared memory object */
    ptr = mmap(0, size, PROT_WRITE, MAP_SHARED, shm_fd, 0);
    struct MyFiles* file = (struct MyStruct*)ptr;

    /*write to first available array slot in shared  memory  object.  Initialize next. */
    for (int i = 0; i < 20; i++)
    {
        if (file[i].fileName == "\0")
        {
            sprintf(file[i]->fileName,"%s",file_name);
            sprintf(file[i]->fileContents,"%s",file_contents);
            file[i + 1]->fileName = "\0";
            file[i + 1]->fileContents = "\0";
            break;
        }
        else if (i == 19)
        {
            prinf("ERROR: The Shared Memory Object is full.\n\n");
            shm unlink(name);
            exit(1);
        }
    }

    /* remove the  shared  memory  object */
    shm unlink(name);

    return 0;
}

PROGRAM #3 (myls.c):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys/shm.h>
#include <sys/stat.h>

struct MyFiles
{
    char *fileName;
    char *fileContents;
};

int main()
{
    char *file_name = argv(0);
    char *file_contents = argv(1);

    int counter = 0;

    /* the size of shared memory object */
    int size = sizeof(struct MyFiles)* 20;

    /* name  of  the  shared  memory  object */
    const  char  *name = "/PROJ4_SHARED_MEM";

    /* shared  memory  file descriptor */
    int shm_fd;

    /* pointer to  shared  memory  object  */
    void  *ptr;

    /* open the  shared  memory  object */
    shm_fd = shm_open(name, O_RDONLY, 0666);

    /* memory map the shared memory object */
    ptr = mmap(0, size, PROT_READ, MAP_SHARED, shm_fd, 0);
    struct MyFiles* file = (struct MyStruct*)ptr;

    if (file[0].fileName == "\0")
    {
            prinf("ERROR: There are no saved files in the shared memory object.\n\n");
            exit(1);
    }

    /*List all filenames */
    while (file[counter].fileName != "\0";)
    {
        prinf("%s \n", file[counter]->fileName);
        counter++;
    }

    /* remove the  shared  memory  object */
    shm unlink(name);

    return 0;
}

回答1:

    struct MyFiles* file = (struct MyStruct*)ptr;

There is apparently a typo, since you have no MyStruct anywhere else in the file. As rici commented, C doesn't require you to cast void* for assignment, so

    struct MyFiles *file = ptr;

suffices.

    file[0]->fileName = "\0";    
    file[0]->fileContents = "\0";

The subscripting [0] already denotes an indirection; the type of file[0] is struct MyFiles, so

    file[0].fileName = "\0";    
    file[0].fileContents = "\0";       

would be correct. However, rici's comment you cannot assume that shared memory will have the same address in every process which shares it is also right, unless you specify the same address (not NULL, system dependent) in every mmap() (and check that the result equals that address). Even then, as Chris Dodd wrote, you never allocate space for the strings. You set them to point at non-shared … strings … - For your project, it would be the easiest way if you allocate a certain amount of space within struct MyFiles:

struct MyFiles
{
    char fileName[12];
    char fileContents[500];
};
…
    /* Initialize first element. */
    // We can well omit this, since newly allocated bytes of a
    // shared memory object are automatically initialized to 0.
    file[0].fileName[0] = '\0';
    file[0].fileContents[0] = '\0';
…
    /* write to first available array slot in shared memory object */
    for (int i = 0; i < 20; i++)
    {
        if (file[i].fileName[0] == '\0')
        {
            sprintf(file[i].fileName, "%11s", file_name);
            sprintf(file[i].fileContents, "%499s", file_contents);
…
    /* List all filenames. */
    while (file[counter].fileName[0] != '\0')
    {
        puts(file[counter]->fileName);
        counter++;
…