Thread: Is this code portable and good "C" code?

  1. #1
    Registered User
    Join Date
    Feb 2018
    Posts
    1

    Question Is this code portable and good "C" code?

    Is the below code good? Especially the memcpy to copy struct A on to struct B? Is this guaranteed to work across platforms (Linux, Mac, Windows GCC/MsVC/Clang compilers etc.)?

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <errno.h>
    
    
    struct A {
        int a;
        int b;
        char c;
        char s[12];
        unsigned long long l;
    };
    
    
    struct B {
        int a;
        int b;
        char c;
    };
    
    
    static void dumpA(struct A* a);
    static void dumpB(struct B* b);
    
    
    static void dumpA(struct A* a)
    {
        if (a != NULL) {
            printf(" %4d %4d %4c %s\n", a->a, a->b, a->c, a->s);
        }
    }
    
    
    static void dumpB(struct B* b)
    {
        if (b != NULL) {
            printf(" %4d %4d %4c\n", b->a, b->b, b->c);
        }
    }
    
    
    int main()
    {
        struct A a;
        struct B b;
        a.a = 10;
        a.b = -2;
        a.c = 'R';
        strncpy(a.s, "Foo", strlen("Foo"));
        memcpy(&b, &a, sizeof(struct B));
        dumpA(&a);
        dumpB(&b);
    
    
        return 0;
    }

  2. #2
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,667
    Well first off, your strncpy() won't append a \0 to your string, so trying to print it out with printf(%s) will fail.
    If you want a strncpy like function which always appends a \0, then you need to write your own.

    The C standard only explicitly guarantees that structs with identical initial members are actually identical when they're declared within a union.
    Code:
    // C99 - 6.5.2.3 Structure and union members
    union {
    	struct {
    		int alltypes;
    	}n;
    	struct {
    		int type;
    		int intnode;
    	} ni;
    	struct {
    		int type;
    		double doublenode;
    	} nf;
    }u;
    u.nf.type = 1;
    u.nf.doublenode = 3.14;
    /*... */
    if (u.n.alltypes == 1)
    	if (sin(u.nf.doublenode) == 0.0)
    /*... */
    Otherwise, if you want to guarantee success, then do this
    Code:
    struct B {
        int a;
        int b;
        char c;
    };
    
    struct A {
        struct B x;
        char s[12];
        unsigned long long l;
    };
    
    int main()
    {
        struct A a;
        struct B b;
    
        a.x.a = 10;
        a.x.b = -2;
        a.x.c = 'R';
        strcpy(a.s, "Foo");
        b = a.x;
        dumpA(&a);
        dumpB(&b);
     
        return 0;
    }
    It's probably one of those "mostly OK", but it sure would be a hell of a bug to find if your guess proves to be wrong in some case.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  3. #3
    misoturbutc Hodor's Avatar
    Join Date
    Nov 2013
    Posts
    1,787
    Quote Originally Posted by Salem View Post
    Well first off, your strncpy() won't append a \0 to your string, so trying to print it out with printf(%s) will fail.
    If you want a strncpy like function which always appends a \0, then you need to write your own.

    The C standard only explicitly guarantees that structs with identical initial members are actually identical when they're declared within a union.
    Code:
    // C99 - 6.5.2.3 Structure and union members
    union {
        struct {
            int alltypes;
        }n;
        struct {
            int type;
            int intnode;
        } ni;
        struct {
            int type;
            double doublenode;
        } nf;
    }u;
    u.nf.type = 1;
    u.nf.doublenode = 3.14;
    /*... */
    if (u.n.alltypes == 1)
        if (sin(u.nf.doublenode) == 0.0)
    /*... */
    Otherwise, if you want to guarantee success, then do this
    Code:
    struct B {
        int a;
        int b;
        char c;
    };
    
    struct A {
        struct B x;
        char s[12];
        unsigned long long l;
    };
    
    int main()
    {
        struct A a;
        struct B b;
    
        a.x.a = 10;
        a.x.b = -2;
        a.x.c = 'R';
        strcpy(a.s, "Foo");
        b = a.x;
        dumpA(&a);
        dumpB(&b);
     
        return 0;
    }
    It's probably one of those "mostly OK", but it sure would be a hell of a bug to find if your guess proves to be wrong in some case.
    I tend to think it's "mostly OK" as well but then I started thinking about strict aliasing rules and I started to doubt and didn't like to answer without reading the somewhat confusing parts of the Standard that are relevant. I wouldn't write the code the way it's written in the original post (not yours) so it's not something that I often think about. Shrug.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 06-09-2017, 12:09 AM
  2. Replies: 1
    Last Post: 05-16-2016, 11:39 AM
  3. Replies: 7
    Last Post: 03-03-2016, 09:13 AM
  4. An interesting code about "struct" in "union"
    By meili100 in forum C++ Programming
    Replies: 3
    Last Post: 04-08-2008, 04:37 AM
  5. errr, is my code "good" ?
    By Shadow in forum C Programming
    Replies: 2
    Last Post: 05-26-2002, 11:13 AM

Tags for this Thread