Is this struct definition right?

Discussion in 'C Programming' started by fl, May 25, 2013.

  1. fl

    fl Guest

    Hi,

    I read the following, which is part of Linux/drivers/pci/pcie/portdrv.h. I do not understand the last definition. It seems there is one parameter missing, i.e.

    struct pci_dev real_struct_variable;


    What do you think?

    Thanks,

    ................
    1 /*
    2 * File: portdrv.h
    3 * Purpose: PCI Express Port Bus Driver's Internal Data Structures
    4 *
    5 * Copyright (C) 2004 Intel
    6 * Copyright (C) Tom Long Nguyen ()
    7 */
    8
    9 #ifndef _PORTDRV_H_
    10 #define _PORTDRV_H_
    11
    12 #include <linux/compiler.h>
    13
    14 #define PCIE_PORT_DEVICE_MAXSERVICES 4
    15 /*
    16 * According to the PCI Express Base Specification 2.0, the indices of
    17 * the MSI-X table entires used by port services must not exceed 31
    18 */
    19 #define PCIE_PORT_MAX_MSIX_ENTRIES 32
    20
    21 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
    22
    23 extern struct bus_type pcie_port_bus_type;
    24 extern int pcie_port_device_register(struct pci_dev *dev);
    25 #ifdef CONFIG_PM
    26 extern int pcie_port_device_suspend(struct device *dev);
    27 extern int pcie_port_device_resume(struct device *dev);
    28 #endif
    29 extern void pcie_port_device_remove(struct pci_dev *dev);
    30 extern int __must_check pcie_port_bus_register(void);
    31 extern void pcie_port_bus_unregister(void);
    32
    33 struct pci_dev;
    fl, May 25, 2013
    #1
    1. Advertising

  2. On Saturday, May 25, 2013 8:00:42 PM UTC+1, fl wrote:
    > Hi,
    >
    >
    >
    > I read the following, which is part of Linux/drivers/pci/pcie/portdrv.h. I
    > do not understand the last definition. It seems there is one parameter
    > missing, i.e.
    >
    > struct pci_dev real_struct_variable;
    >
    > 33 struct pci_dev;
    >


    It's a tentative forward declaration. It reserves the structure name
    pci_dev, without actually declaring it. So you can declare pointers to
    it and if you try to redefine it the program will break. But you
    don't know what members it has.
    Malcolm McLean, May 25, 2013
    #2
    1. Advertising

  3. fl

    Philip Lantz Guest

    Malcolm McLean wrote:
    > fl wrote:
    > >
    > > struct pci_dev;
    > >

    >
    > It's a tentative forward declaration. It reserves the structure name
    > pci_dev, without actually declaring it. So you can declare pointers to
    > it and if you try to redefine it the program will break. But you
    > don't know what members it has.


    I'm curious what you mean by "if you try to redefine it the program will
    break."

    After the above declaration, you can do any or all of the following:

    struct pci_dev;
    struct pci_dev { int x; };
    void z() { struct pci_dev { double y; }; }

    So, what are you thinking of that "will break"?
    Philip Lantz, May 25, 2013
    #3
  4. On Saturday, May 25, 2013 9:41:12 PM UTC+1, Philip Lantz wrote:
    > Malcolm McLean wrote:
    >
    > > fl wrote:

    >
    > > > struct pci_dev;

    >
    > > >

    >
    > >

    >
    > > It's a tentative forward declaration. It reserves the structure name

    >
    > > pci_dev, without actually declaring it. So you can declare pointers to

    >
    > > it and if you try to redefine it the program will break. But you

    >
    > > don't know what members it has.

    >
    >
    >
    > I'm curious what you mean by "if you try to redefine it the program will
    >
    > break."
    >
    >
    >
    > After the above declaration, you can do any or all of the following:
    >
    >
    >
    > struct pci_dev;
    >
    > struct pci_dev { int x; };
    >
    > void z() { struct pci_dev { double y; }; }
    >
    >
    >
    > So, what are you thinking of that "will break"?
    >

    I was wrong.
    I thought it prevented a redeclaration of the same symbol, but it doesn't
    provide any such protection.
    Malcolm McLean, May 25, 2013
    #4
  5. fl

    Eric Sosman Guest

    On 5/25/2013 3:00 PM, fl wrote:
    > Hi,
    >
    > I read the following, which is part of Linux/drivers/pci/pcie/portdrv.h. I do not understand the last definition. It seems there is one parameter missing, i.e.
    >
    > struct pci_dev real_struct_variable;
    >
    >
    > What do you think?
    >
    > Thanks,
    >
    > ...............
    > 1 /*
    > 2 * File: portdrv.h
    > 3 * Purpose: PCI Express Port Bus Driver's Internal Data Structures
    > 4 *
    > 5 * Copyright (C) 2004 Intel
    > 6 * Copyright (C) Tom Long Nguyen ()
    > 7 */
    > 8
    > 9 #ifndef _PORTDRV_H_
    > 10 #define _PORTDRV_H_
    > 11
    > 12 #include <linux/compiler.h>
    > 13
    > 14 #define PCIE_PORT_DEVICE_MAXSERVICES 4
    > 15 /*
    > 16 * According to the PCI Express Base Specification 2.0, the indices of
    > 17 * the MSI-X table entires used by port services must not exceed 31
    > 18 */
    > 19 #define PCIE_PORT_MAX_MSIX_ENTRIES 32
    > 20
    > 21 #define get_descriptor_id(type, service) (((type - 4) << 4) | service)
    > 22
    > 23 extern struct bus_type pcie_port_bus_type;
    > 24 extern int pcie_port_device_register(struct pci_dev *dev);
    > 25 #ifdef CONFIG_PM
    > 26 extern int pcie_port_device_suspend(struct device *dev);
    > 27 extern int pcie_port_device_resume(struct device *dev);
    > 28 #endif
    > 29 extern void pcie_port_device_remove(struct pci_dev *dev);
    > 30 extern int __must_check pcie_port_bus_register(void);
    > 31 extern void pcie_port_bus_unregister(void);
    > 32
    > 33 struct pci_dev;


    Line 33 declares the existence of a type `struct pci_dev', but
    omits the details of its makeup; it is an "incomplete type." There
    are essentially only two things you can do with an incomplete type:

    - You can make pointer variables that point to it. You can't
    point them at anything useful, because you can't create an
    actual `struct pci_dev' object: For starters, the compiler
    doesn't know how much memory it needs. But you can create
    a `struct pci_dev *ptr;' variable, and if somebody magically
    hands you a suitable value you can store it, copy it, move
    it around, and hand it onward to other functions.

    - You can complete it by writing another declaration, this one
    with all the innards (the struct or union members, the actual
    dimension of an array, et cetera).

    So, what's the point? It's C's idiom for "opaque" or "abstract"
    data types. Think of FILE, for example: <stdio.h> declares the FILE
    type, declares functions like fopen() that return FILE* pointers, and
    declares functions like fprintf() that accept them. You can call
    fopen() and get back a FILE* pointer value, you can store it in a FILE*
    variable, and you can pass the stored value to rewind() and putc() and
    fclose() -- all without needing to worry about what the actual FILE
    looks like. If somebody enhances the <stdio.h> machinery and needs
    to change the internals of a FILE, you needn't worry: All that stuff
    is internal to the C library, and you're happy to pass pointers around
    without fretting over precisely what they point at.

    (Disclaimer: FILE is not a perfect example. There's a quirk in
    the wording of the C Standard that requires FILE *not* to be an
    incomplete type -- but it's used just as if it were, by user-level
    code at any rate. It's a familiar example of how one uses an
    incomplete type, even though FILE is not actually incomplete.)

    Back to the code that puzzles you: You've got an incomplete
    type `struct pci_dev', and you've got several functions that take
    `struct pci_dev*' pointers as arguments. Somewhere -- maybe later
    in the same file, maybe in some other file -- there's probably a
    function or two that "creates" or "allocates" or "reserves" a PCI
    device and returns a `struct pci_dev*' pointer, in very much the
    same way that fopen() returns a FILE*. Somewhere else there's
    surely an actual fleshing-out of the `struct pci_dev', hidden away
    in the innards of the PCI implementation where the PCI mavens can
    muck with it and not disturb the callers who only care about the
    pointers that get handed around.

    Meanwhile, *I'm* puzzled by one feature of the code you show,
    and hope the experts will chime in. O Experts: Since lines 24, 26,
    27, and 29 mention `struct pci_dev*' in the function prototypes,
    do these functions actually accept pointers to the type declared
    in line 33? Absent any earlier `struct pci_dev' declaration,
    aren't the others at "function prototype scope?"

    --
    Eric Sosman
    d
    Eric Sosman, May 25, 2013
    #5
  6. Malcolm McLean <> writes:
    > On Saturday, May 25, 2013 9:41:12 PM UTC+1, Philip Lantz wrote:
    >> Malcolm McLean wrote:
    >> > fl wrote:
    >> > > struct pci_dev;
    >> >
    >> > It's a tentative forward declaration. It reserves the structure name
    >> > pci_dev, without actually declaring it. So you can declare pointers to
    >> > it and if you try to redefine it the program will break. But you
    >> > don't know what members it has.

    >>
    >> I'm curious what you mean by "if you try to redefine it the program will
    >> break."
    >>
    >> After the above declaration, you can do any or all of the following:
    >>
    >> struct pci_dev;
    >>
    >> struct pci_dev { int x; };
    >>
    >> void z() { struct pci_dev { double y; }; }
    >>
    >> So, what are you thinking of that "will break"?
    >>

    > I was wrong.
    > I thought it prevented a redeclaration of the same symbol, but it doesn't
    > provide any such protection.


    It's an odd kind of "protection" you had in mind. The whole point of
    being to declare an incomplete type like "struct pci_dev;" is that you
    can complete the type later with a full definition.

    (I'm not criticizing you for being wrong; it happens to all of us.)

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, May 25, 2013
    #6
  7. Eric Sosman <> writes:
    [...]
    > Meanwhile, *I'm* puzzled by one feature of the code you show,
    > and hope the experts will chime in. O Experts: Since lines 24, 26,
    > 27, and 29 mention `struct pci_dev*' in the function prototypes,
    > do these functions actually accept pointers to the type declared
    > in line 33? Absent any earlier `struct pci_dev' declaration,
    > aren't the others at "function prototype scope?"


    Yes, that is puzzling. There is a full definition of "struct
    pci_dev" in linux/include/linux/pci.h. My best guess is that the
    full definition is made visible by the "#include <linux/compiler.h>"
    near the top of the file -- but in that case the "forward"
    declaration would be unnecessary.

    I've found the commit where the declaration was added; I'll send an
    e-mail to the authors (or approvers) of that commmit and ask about it.

    --
    Keith Thompson (The_Other_Keith <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, May 26, 2013
    #7
  8. On Sat, 25 May 2013 18:11:53 -0700, Keith Thompson wrote:

    > Eric Sosman <> writes: [...]
    >> Meanwhile, *I'm* puzzled by one feature of the code you show,
    >> and hope the experts will chime in. O Experts: Since lines 24, 26, 27,
    >> and 29 mention `struct pci_dev*' in the function prototypes, do these
    >> functions actually accept pointers to the type declared in line 33?
    >> Absent any earlier `struct pci_dev' declaration, aren't the others at
    >> "function prototype scope?"

    >
    > Yes, that is puzzling. There is a full definition of "struct pci_dev"
    > in linux/include/linux/pci.h. My best guess is that the full definition
    > is made visible by the "#include <linux/compiler.h>" near the top of the
    > file -- but in that case the "forward" declaration would be unnecessary.


    My guess is that they rely on the type compatibility rules.
    If the definition of struct pci_dev (also) can be found in a different
    translation unit, then clause 6.2.7/1 (C99) stipulates that each of the
    prototype-scope declarations of struct pci_dev is individually compatible
    with the definition in the other TU on the grounds that they occur in
    different TU's and have the same tag.

    It is not a stretch to conjecture that if several declarations are each
    individually compatible with an additional declaration in a different TU,
    that they are also compatible with each other, even though this is not
    backed up by the standard.

    Bart v Ingen Schenau
    Bart van Ingen Schenau, May 26, 2013
    #8
  9. "christian.bau" <> writes:
    > On May 25, 10:14 pm, Eric Sosman <>
    > wrote:
    >>      Meanwhile, *I'm* puzzled by one feature of the code you show,
    >> and hope the experts will chime in.  O Experts: Since lines 24, 26,
    >> 27, and 29 mention `struct pci_dev*' in the function prototypes,
    >> do these functions actually accept pointers to the type declared
    >> in line 33?  Absent any earlier `struct pci_dev' declaration,
    >> aren't the others at "function prototype scope?"

    >
    > It's incorrect C; the "struct pci_dev" in the function prototype is
    > not the same as the one defined later.
    >
    > In my experience, older compilers just accepted this, then compilers
    > gave warnings about it (which many programmers didn't understand), and
    > then programmers learned to put a "struct pci_dev" in front of such a
    > prototype, either to get rid of the warning, or because they figured
    > out why the warning was there and why the code was actually wrong. So
    > the OP either uses an old compiler, or is lax with his attitude
    > towards compiler warnings.


    Not necessarily. If struct pci_dev is *also* declared prior to the
    first reference to it in that file, then the "struct pci_dev;" near the
    bottom of the file is just a redundant declaration, and all instances of
    "struct pci_dev" refer to the same type.

    Looking at the git history of that particular file, earlier versions
    refer to "struct pci_dev" *without* declaring it in the file.

    I've sent an e-mail to the authors of the change that introduced that
    declaration, but I haven't heard back from them yet.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, May 28, 2013
    #9
  10. On May 25, 8:11 pm, Keith Thompson <> wrote:
    > Eric Sosman <> writes:
    >
    > [...]
    >
    > >      Meanwhile, *I'm* puzzled by one feature of the code you show,
    > > and hope the experts will chime in.  O Experts: Since lines 24, 26,
    > > 27, and 29 mention `struct pci_dev*' in the function prototypes,
    > > do these functions actually accept pointers to the type declared
    > > in line 33?  Absent any earlier `struct pci_dev' declaration,
    > > aren't the others at "function prototype scope?"

    >
    > Yes, that is puzzling.  There is a full definition of "struct
    > pci_dev" in linux/include/linux/pci.h.  My best guess is that the
    > full definition is made visible by the "#include <linux/compiler.h>"
    > near the top of the file -- but in that case the "forward"
    > declaration would be unnecessary.
    >
    > I've found the commit where the declaration was added; I'll send an
    > e-mail to the authors (or approvers) of that commmit and ask about it.
    >


    Are you referring to this or some other revision:

    https://github.com/torvalds/linux/b...80c4804d4515d05c64/drivers/pci/pcie/portdrv.h

    Initially it appeared to me that the function prototypes were added
    more than two years after the tentative declaration. A little more
    attention showed that it was only modification (removing the "extern")
    to already existing prototypes, and the so called "forward"
    declaration was added 'later' (pun intended).

    - Anand
    Anand Hariharan, May 28, 2013
    #10
  11. Anand Hariharan <> writes:
    > On May 25, 8:11 pm, Keith Thompson <> wrote:
    >> Eric Sosman <> writes:
    >>
    >> [...]
    >>
    >> >      Meanwhile, *I'm* puzzled by one feature of the code you show,
    >> > and hope the experts will chime in.  O Experts: Since lines 24, 26,
    >> > 27, and 29 mention `struct pci_dev*' in the function prototypes,
    >> > do these functions actually accept pointers to the type declared
    >> > in line 33?  Absent any earlier `struct pci_dev' declaration,
    >> > aren't the others at "function prototype scope?"

    >>
    >> Yes, that is puzzling.  There is a full definition of "struct
    >> pci_dev" in linux/include/linux/pci.h.  My best guess is that the
    >> full definition is made visible by the "#include <linux/compiler.h>"
    >> near the top of the file -- but in that case the "forward"
    >> declaration would be unnecessary.
    >>
    >> I've found the commit where the declaration was added; I'll send an
    >> e-mail to the authors (or approvers) of that commmit and ask about it.

    >
    > Are you referring to this or some other revision:
    >
    > https://github.com/torvalds/linux/b...80c4804d4515d05c64/drivers/pci/pcie/portdrv.h


    That's the one.

    > Initially it appeared to me that the function prototypes were added
    > more than two years after the tentative declaration. A little more
    > attention showed that it was only modification (removing the "extern")
    > to already existing prototypes, and the so called "forward"
    > declaration was added 'later' (pun intended).


    Yes, the prototypes were there before the "struct pci_dev;" declaration
    was added. Which suggests either that the "struct pci_dev;" declaration
    was unnecessary (that's my guess), or that it was made necessary by some
    other change -- though the latter wouldn't explain why the declaration
    was added *after* the prototypes. That commit affected 17 files.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    Working, but not speaking, for JetHead Development, Inc.
    "We must do something. This is something. Therefore, we must do this."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
    Keith Thompson, May 28, 2013
    #11
  12. fl

    Tim Rentsch Guest

    Malcolm McLean <> writes:

    > On Saturday, May 25, 2013 8:00:42 PM UTC+1, fl wrote:
    >>
    >> I read the following, which is part of Linux/drivers/pci/pcie/portdrv.h. I
    >> do not understand the last definition. It seems there is one parameter
    >> missing, i.e.
    >>
    >> struct pci_dev real_struct_variable;
    >>
    >> 33 struct pci_dev;

    >
    > It's a tentative forward declaration. It reserves the structure
    > name pci_dev, without actually declaring it. So you can declare
    > pointers to it and if you try to redefine it the program will break.
    > But you don't know what members it has.


    There is no such thing as a "tentative" declaration, or
    "forward" declaration either as far ISO C is concerned.
    This line is simply a declaration - it declares a type
    whose struct tag is 'pci_dev' (and if no other previous
    declaration of the same type is visible "creates" it),
    so any subsequent references to a type whose struct tag
    is 'pci_dev' use the type declared here rather than
    accidentally declaring a new one (which would necessarily
    have a more limited scope), as might happen if there were
    no previous declaration.

    The phrase you're looking for is this declaration does
    not _define the contents of_ the type, ie, what members
    the struct contains. But in terms of declaring the type
    this is just a regular declaration.
    Tim Rentsch, Jun 12, 2013
    #12
  13. fl

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > (I'm not criticizing you for being wrong; it happens to all of us.)


    It does, but it happens to some people a lot more
    than others.
    Tim Rentsch, Jun 12, 2013
    #13
  14. fl

    Tim Rentsch Guest

    Bart van Ingen Schenau <> writes:

    > On Sat, 25 May 2013 18:11:53 -0700, Keith Thompson wrote:
    >
    >> Eric Sosman <> writes: [...]
    >>> Meanwhile, *I'm* puzzled by one feature of the code you show,
    >>> and hope the experts will chime in. O Experts: Since lines 24, 26, 27,
    >>> and 29 mention `struct pci_dev*' in the function prototypes, do these
    >>> functions actually accept pointers to the type declared in line 33?
    >>> Absent any earlier `struct pci_dev' declaration, aren't the others at
    >>> "function prototype scope?"

    >>
    >> Yes, that is puzzling. There is a full definition of "struct pci_dev"
    >> in linux/include/linux/pci.h. My best guess is that the full definition
    >> is made visible by the "#include <linux/compiler.h>" near the top of the
    >> file -- but in that case the "forward" declaration would be unnecessary.

    >
    > My guess is that they rely on the type compatibility rules. If the
    > definition of struct pci_dev (also) can be found in a different
    > translation unit, then clause 6.2.7/1 (C99) stipulates that each of
    > the prototype-scope declarations of struct pci_dev is individually
    > compatible with the definition in the other TU on the grounds that
    > they occur in different TU's and have the same tag.


    A little thought should convince you that this isn't right. If
    there is no previous declaration of struct pci_dev, then the
    parameters of the preceding functions have types that cannot be
    satisfied by any other struct pointer type; arguments other than
    null pointer constants or (void *) would be violate a constraint.
    Of course it's possible that the compiler is run in a way so
    that the constraint violation is ignorable, and the developers
    do in fact ignore it, but that isn't really very likely.

    > It is not a stretch to conjecture that if several declarations are
    > each individually compatible with an additional declaration in a
    > different TU, that they are also compatible with each other, even
    > though this is not backed up by the standard.


    The problem is not compatibility with other TU's, the problem
    is the constraint violations that occur within a single TU
    because of the (putative) multiple, non-compatible types
    involved.
    Tim Rentsch, Jun 12, 2013
    #14
  15. fl

    Tim Rentsch Guest

    Eric Sosman <> writes:

    > Meanwhile, *I'm* puzzled by one feature of the code you
    > show, and hope the experts will chime in. O Experts: Since
    > lines 24, 26, 27, and 29 mention `struct pci_dev*' in the
    > function prototypes, do these functions actually accept
    > pointers to the type declared in line 33? Absent any earlier
    > `struct pci_dev' declaration, aren't the others at "function
    > prototype scope?"


    Yes, they are. Moreover, since they are, any attempt to
    supply an argument to one of these functions (and assuming
    there is no earlier declaration of struct pci_dev) will
    result in a constraint violation (not counting the obvious
    circumstances of giving a null pointer constant or an
    expression of type (void *) as an argument). So in all
    likelihood any TU that includes this file either has a
    previous declaration of struct pci_dev or does not call
    these functions.
    Tim Rentsch, Jun 12, 2013
    #15
  16. On Wed, 12 Jun 2013 15:24:50 -0700, Tim Rentsch wrote:

    > Eric Sosman <> writes:
    >
    >> Meanwhile, *I'm* puzzled by one feature of the code you
    >> show, and hope the experts will chime in. O Experts: Since lines 24,
    >> 26, 27, and 29 mention `struct pci_dev*' in the function prototypes, do
    >> these functions actually accept pointers to the type declared in line
    >> 33? Absent any earlier `struct pci_dev' declaration, aren't the others
    >> at "function prototype scope?"

    >
    > Yes, they are. Moreover, since they are, any attempt to supply an
    > argument to one of these functions (and assuming there is no earlier
    > declaration of struct pci_dev) will result in a constraint violation
    > (not counting the obvious circumstances of giving a null pointer
    > constant or an expression of type (void *) as an argument). So in all
    > likelihood any TU that includes this file either has a previous
    > declaration of struct pci_dev or does not call these functions.


    Or, as a third possibility, the compiler (settings) used to compile the
    software is non-conforming in that it does not diagnose the constraint
    violation.

    Bart v Ingen Schenau
    Bart van Ingen Schenau, Jun 13, 2013
    #16
  17. fl

    Tim Rentsch Guest

    Keith Thompson <> writes:

    > Anand Hariharan <> writes:
    >> On May 25, 8:11 pm, Keith Thompson <> wrote:
    >>> Eric Sosman <> writes:
    >>>
    >>> [...]
    >>>
    >>> > Meanwhile, *I'm* puzzled by one feature of the code you show,
    >>> > and hope the experts will chime in. O Experts: Since lines 24, 26,
    >>> > 27, and 29 mention `struct pci_dev*' in the function prototypes,
    >>> > do these functions actually accept pointers to the type declared
    >>> > in line 33? Absent any earlier `struct pci_dev' declaration,
    >>> > aren't the others at "function prototype scope?"
    >>>
    >>> Yes, that is puzzling. There is a full definition of "struct
    >>> pci_dev" in linux/include/linux/pci.h. My best guess is that the
    >>> full definition is made visible by the "#include <linux/compiler.h>"
    >>> near the top of the file -- but in that case the "forward"
    >>> declaration would be unnecessary.
    >>>
    >>> I've found the commit where the declaration was added; I'll send an
    >>> e-mail to the authors (or approvers) of that commmit and ask about it.

    >>
    >> Are you referring to this or some other revision:
    >>
    >> https://github.com/torvalds/linux/b...80c4804d4515d05c64/drivers/pci/pcie/portdrv.h

    >
    > That's the one.
    >
    >> Initially it appeared to me that the function prototypes were
    >> added more than two years after the tentative declaration. A
    >> little more attention showed that it was only modification
    >> (removing the "extern") to already existing prototypes, and the
    >> so called "forward" declaration was added 'later' (pun intended).

    >
    > Yes, the prototypes were there before the "struct pci_dev;"
    > declaration was added. Which suggests either that the "struct
    > pci_dev;" declaration was unnecessary (that's my guess), or that
    > it was made necessary by some other change -- though the latter
    > wouldn't explain why the declaration was added *after* the
    > prototypes. That commit affected 17 files.


    Here is a plausible (and also I think reasonably likely)
    explanation.

    The file portdrv.h was included in two kinds of circumstances:
    one, where the declared functions were called, but the TU did an
    include of pci.h before the include of portdrv.h, so the earlier
    declarations in portdrv.h were okay; and two, where there was
    no earlier include of pci.h, but the offending declarations were
    not made use of, so it didn't matter that there was no earlier
    declaration of struct pci_dev -- everything compiled fine, and
    it all worked because the funny declarations weren't used in
    places where they would have done something bad.

    At some point, the file portdrv.h was modified to have some
    definitions of inline functions. These function bodies make use
    of some of the earlier declarations using struct pci_dev. This
    caused problems in those TU's where there was no earlier include
    for pci.h -- even though they didn't use any of the offending
    declarations themselves, the newly added inline definitions in
    portdrv.h do, and that caused compilation errors. These errors
    can be fixed (I believe -- I haven't tried compiling myself) by
    adding the 'struct pci_dev;' declaration where it appears in
    portdrv.h. The declaration was put in, the errors disappeared,
    and that's how it was left; since everything was compiling and
    working okay, the curious placement of the 'struct pci_dev;'
    declaration was just left where it was.

    Evidence to support this suggestion: AFAICT the inline function
    definitions and the 'struct pci_dev;' declaration appeared in the
    same revision of portdrv.h. Since the inline function definitions
    use some (but only some!) of the earlier declarations, it seems
    like a good guess that portdrv.h had been included in some places
    where the lack of an earlier declaration of struct pci_dev didn't
    matter, but now because of the just-added inline function bodies
    it did. And it's easy to imagine that someone added the line with
    the declaration of struct pci_dev just early enough to resolve the
    problems caused by those new function bodies.
    Tim Rentsch, Jun 13, 2013
    #17
  18. fl

    Tim Rentsch Guest

    Bart van Ingen Schenau <> writes:

    > On Wed, 12 Jun 2013 15:24:50 -0700, Tim Rentsch wrote:
    >
    >> Eric Sosman <> writes:
    >>
    >>> Meanwhile, *I'm* puzzled by one feature of the code you
    >>> show, and hope the experts will chime in. O Experts: Since
    >>> lines 24, 26, 27, and 29 mention `struct pci_dev*' in the
    >>> function prototypes, do these functions actually accept pointers
    >>> to the type declared in line 33? Absent any earlier `struct
    >>> pci_dev' declaration, aren't the others at "function prototype
    >>> scope?"

    >>
    >> Yes, they are. Moreover, since they are, any attempt to
    >> supply an argument to one of these functions (and assuming
    >> there is no earlier declaration of struct pci_dev) will
    >> result in a constraint violation (not counting the obvious
    >> circumstances of giving a null pointer constant or an
    >> expression of type (void *) as an argument). So in all
    >> likelihood any TU that includes this file either has a
    >> previous declaration of struct pci_dev or does not call
    >> these functions.

    >
    > Or, as a third possibility, the compiler (settings) used to
    > compile the software is non-conforming in that it does not
    > diagnose the constraint violation.


    No, there are only those two possibilities that avoid being a
    constraint violation. Using non-conforming compiler settings
    doesn't alter whether a given piece of code has a constraint
    violation (and my earlier comments don't say anything about
    diagnostics).

    More to the point, the idea that compiler settings were used
    which avoided issuing any diagnostics for such code is highly
    unlikely. Linux is compiled using gcc (among others). Every
    setting of compiler options I tried with gcc, including the least
    conforming ones I could think of, all produced a diagnostic (or
    more than one) in such cases. So unless whoever was doing the
    builds for that code was ignoring some of the warnings (which
    of course is also a possibility), the most likely circumstance
    is that any TU having a #include "portdrv.h" also had an earlier
    declaration of struct pci_dev, ie, fixing the problem with
    function declarations that have a struct pci_dev * parameter.
    Tim Rentsch, Jun 15, 2013
    #18
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Jianli Shen
    Replies:
    1
    Views:
    587
    Victor Bazarov
    Mar 13, 2005
  2. Chris Fogelklou
    Replies:
    36
    Views:
    1,373
    Chris Fogelklou
    Apr 20, 2004
  3. Ark
    Replies:
    1
    Views:
    415
    Chris Torek
    Aug 7, 2004
  4. Jon Slaughter
    Replies:
    4
    Views:
    449
    Jon Slaughter
    Oct 26, 2005
  5. Pierre Yves
    Replies:
    2
    Views:
    482
    Pierre Yves
    Jan 10, 2008
Loading...

Share This Page