Regarding typedefs of 1-element arrays in C

前端 未结 2 460
自闭症患者
自闭症患者 2020-12-17 19:50

Sometimes, in C, you do this:

typedef struct foo {
   unsigned int some_data;
} foo; /* btw, foo_t is discouraged */
         


        
相关标签:
2条回答
  • 2020-12-17 20:44

    The only advantage to this method is nicer looking code and easier typing. It allows the user to create the struct on the stack without dynamic allocation like so:

    foo bar;
    

    However, the structure can still be passed to functions that require a pointer type, without requiring the user to convert to a pointer with &bar every time.

    foo_init(bar);
    

    Without the 1 element array, it would require either an alloc function as you mentioned, or constant & usage.

    foo_init(&bar);
    

    The only pitfall I can think of is the normal concerns associated with direct stack allocation. If this in a library used by other code, updates to the struct may break client code in the future, which would not happen when using an alloc free pair.

    0 讨论(0)
  • 2020-12-17 20:48

    This is very clever (but see below).

    It encourages the misleading idea that C function arguments can be passed by reference.

    If I see this in a C program:

    foo bar;
    foo_init(bar);
    

    I know that the call to foo_init does not modify the value of bar. I also know that the code passes the value of bar to a function when it hasn't initialized it, which is very probably undefined behavior.

    Unless I happen to know that foo is a typedef for an array type. Then I suddenly realize that foo_init(bar) is not passing the value of bar, but the address of its first element. And now every time I see something that refers to type foo, or to an object of type foo, I have to think about how foo was defined as a typedef for a single-element array before I can understand the code.

    It is an attempt to make C look like something it's not, not unlike things like:

    #define BEGIN {
    #define END }
    

    and so forth. And it doesn't result in code that's easier to understand because it uses features that C doesn't support directly. It results in code that's harder to understand (especially to readers who know C well), because you have to understand both the customized declarations and the underlying C semantics that make the whole thing work.

    If you want to pass pointers around, just pass pointers around, and do it explicitly. See, for example, the use of FILE* in the various standard functions defined in <stdio.h>. There is no attempt to hide pointers behind macros or typedefs, and C programmers have been using that interface for decades.

    If you want to write code that looks like it's passing arguments by reference, define some function-like macros, and give them all-caps names so knowledgeable readers will know that something odd is going on.

    I said above that this is "clever". I'm reminded of something I did when I was first learning the C language:

    #define EVER ;;
    

    which let me write an infinite loop as:

    for (EVER) {
        /* ... */
    }
    

    At the time, I thought it was clever.

    I still think it's clever. I just no longer think that's a good thing.

    0 讨论(0)
提交回复
热议问题