Problems with .h files, conatants and globals

Discussion in 'C Programming' started by Ruud Baltissen, Sep 28, 2013.

  1. Hello,


    I have decided to port some Turbo Pascal programs to C/C++. Most of them are Commodore related, for example: a drive simulator, and should run under DOS. I have developed various units and I have troubles converting them to C.. Not converting the code itself but defining the .h files and using them.

    I have one unit, RB_unit.pas, that contains general functions, for example:deleting the white space at both ends of a string. A second one, CBM_unit.pas only contains Commodore related functions, for example: a function to read a byte from the IEEE bus. The main program can call functions from bothRB_unit and CBM_unit. CBM_unit can call functions from RB_unit as well. Inboth units I declared some global variables. In cbm_unit.h I declared a structure with drive properties. In CBM_unit.pas I declared:
    Device : array[0..coMaxDevice] of ^TEmuDevice;
    I translated this to:
    struct EmuDeviceStr Device[coMaxDevice];

    What did I do more: I declared 'byte' in RB_unit.h. I don't know if I keep it but for the moment I use it to learn how to work with .h files.
    I also declared a constant there: const char chcsep = '/';


    The problems:
    If I write the next text in the main function, everything is allright:

    byte b1, b2;
    struct EmuDeviceStr Device[coMaxDevice];

    for (b1 = 0; b1 < coMaxDevice; b1++)
    for (b2 = 0; b1 < 2; b1++)
    Device[b1].Drv[b2].InUse = False;

    But if I write it in a (now empty) function in CBM_unit.c, I get errors. The first one is that cbm_unit doesn't know 'byte'. Quite logical, because I didn't include rb_unit.h yet. But if I include it, I get several errors. I deleted the 'for' construction but then got this error: "multiple definition of `chcsep'".
    Commenting out this const declaration worked again (except two warnings notusing B1 and b2) but then my question: what do I wrong or where should I declare this const then?

    Adding 'for' construction again produced the several error; both 'coMaxDevice' and 'Device' are undeclared. Both have been declared in cbm_unit.h. So I included cbm_unit.h but that resulted in more "multiple definition" errors :(

    Next problem: I know I have to declare 'struct EmuDeviceStr Device[coMaxDevice];' somewhere outside 'main', IMHO in cbm_unit.c. But if I do I get the error "variably modified 'Device' at file scope".

    I can only say now: PLEASE, HELP !!!

    Many thanks in advance!


    Kind regards, Ruud Baltissen
    www.Baltissen.org
    Ruud Baltissen, Sep 28, 2013
    #1
    1. Advertising

  2. Ruud Baltissen <> writes:

    Your post is long, but I want to comment on only one point early to try
    to head off too much wasted time:

    > I have decided to port some Turbo Pascal programs to C/C++.


    You need to decide if you are writing C or C++. Most people think that
    unless they uses classes the two are the same, but they aren't. In
    particular:

    > What did I do more: I declared 'byte' in RB_unit.h. I don't know if I
    > keep it but for the moment I use it to learn how to work with .h
    > files.
    > I also declared a constant there: const char chcsep = '/';


    The way C and C++ handle consts, particularly when they are in a header
    file, is different in significant ways. You need to pick C or C++ and
    stick with that (both have active news groups).

    <snip>
    --
    Ben.
    Ben Bacarisse, Sep 28, 2013
    #2
    1. Advertising

  3. Ruud Baltissen

    James Kuyper Guest

    On 09/28/2013 06:46 AM, Ruud Baltissen wrote:
    > Hello,
    >
    >
    > I have decided to port some Turbo Pascal programs to C/C++. Most of


    There is no such thing as C/C++. There's C, and there's C++, two
    different languages with a lot of similarities, but also some important
    differences - some of which are relevant to your complaints below. You
    have to choose one of the following options:
    1. port to C
    2. port to C++
    3. write code compatible with both C and C++, with the same meaning in
    both languages. This is not as trivial as it sounds.
    4. Do two different ports: one for C, and one for C++.

    ....
    > What did I do more: I declared 'byte' in RB_unit.h. I don't know if I
    > keep it but for the moment I use it to learn how to work with .h
    > files. I also declared a constant there: const char chcsep = '/';


    That's a problem. The usual reason for putting something in a header
    file is that it will be needed in multiple different translation units.
    That declaration, presumably at file scope, will create a separate
    definition of an object with external linkage named chcsep in each
    translation unit that #includes that header. That's not allowed, you can
    only have one such object defined in your entire program. You can have
    multiple declarations for such an object, but only one definition.
    Converting that into a non-defining declaration requires adding the
    keyword 'extern', and removing the initialization. As a result, the
    value of chcsep would not be known at compile time. You should use the
    preprocessor instead:

    #define CHCSEP '/'

    In C++, your definition would be fine, because a file scope object that
    is declared const or constexpr, and is not declared 'extern', has
    internal linkage (C++ 3.5p3). Any decent implementation of C++ won't
    waste space storing such an object unless it is used in a way that
    requires the object to actually exist, such as taking it's address.
    Otherwise, it's essentially equivalent to CHCSEP. That's true, in part,
    because an object declared const and initialized with an constant
    expression can itself be used as a constant expression (C++ 5.19p2).
    Neither of those rules apply to C.

    ....
    > But if I write it in a (now empty) function in CBM_unit.c, I get
    > errors. The first one is that cbm_unit doesn't know 'byte'. Quite
    > logical, because I didn't include rb_unit.h yet. But if I include it,
    > I get several errors. ...


    That should be the right solution to this problem. The fact that you got
    error messages implies that there's something else involved that you
    haven't told us about rb_unit.h. You should have given us the exact text
    of the error messages - then we might be able to figure out what the
    real problem is.

    > ... I deleted the 'for' construction but then got
    > this error: "multiple definition of `chcsep'".


    If you got that message at link time, then it's precisely the problem
    that I warned you about above.
    However, if you got that message at compile time, it suggests that
    you're #including rb_unit.h at least twice, and that you haven't
    inserted a header guard in that file.
    --
    James Kuyper
    James Kuyper, Sep 28, 2013
    #3
  4. Ruud Baltissen

    Rosario1903 Guest

    On Sat, 28 Sep 2013 03:46:45 -0700 (PDT), Ruud Baltissen
    <> wrote:


    > for (b1 = 0; b1 < coMaxDevice; b1++)
    > for (b2 = 0; b1 < 2; b1++)
    > Device[b1].Drv[b2].InUse = False;


    if coMaxDevice>=1 this is equivalent to

    Device[0].Drv[0].InUse = False;
    Device[1].Drv[0].InUse = False;

    there would be something not ok in that loop
    Rosario1903, Sep 28, 2013
    #4
  5. James Kuyper <> wrote:

    (snip)

    > There is no such thing as C/C++. There's C, and there's C++, two
    > different languages with a lot of similarities, but also some important
    > differences - some of which are relevant to your complaints below. You
    > have to choose one of the following options:
    > 1. port to C
    > 2. port to C++
    > 3. write code compatible with both C and C++, with the same meaning in
    > both languages. This is not as trivial as it sounds.
    > 4. Do two different ports: one for C, and one for C++.



    5. A program that is partly in C and partly in C++, usually because
    more than one person worked on it.

    -- glen
    glen herrmannsfeldt, Sep 28, 2013
    #5
  6. James Kuyper <> writes:
    > On 09/28/2013 06:46 AM, Ruud Baltissen wrote:

    [...]
    >> What did I do more: I declared 'byte' in RB_unit.h. I don't know if I
    >> keep it but for the moment I use it to learn how to work with .h
    >> files. I also declared a constant there: const char chcsep = '/';

    >
    > That's a problem. The usual reason for putting something in a header
    > file is that it will be needed in multiple different translation units.
    > That declaration, presumably at file scope, will create a separate
    > definition of an object with external linkage named chcsep in each
    > translation unit that #includes that header. That's not allowed, you can
    > only have one such object defined in your entire program. You can have
    > multiple declarations for such an object, but only one definition.
    > Converting that into a non-defining declaration requires adding the
    > keyword 'extern', and removing the initialization. As a result, the
    > value of chcsep would not be known at compile time. You should use the
    > preprocessor instead:
    >
    > #define CHCSEP '/'


    Or:

    enum { chcsep = '/' };

    This is a hack that depends on a couple of quirks of C: that both
    enumerators and character constants are constant expressions of type
    int.

    --
    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, Sep 28, 2013
    #6
  7. On Sat, 28 Sep 2013 03:46:45 -0700 (PDT), Ruud Baltissen
    <> wrote:

    >I have one unit, RB_unit.pas, that contains general functions, for example: deleting the white space at both ends of a string. A second one, CBM_unit.pas only contains Commodore related functions, for example: a function to read a byte from the IEEE bus. The main program can call functions from both RB_unit and CBM_unit. CBM_unit can call functions from RB_unit as well. In both units I declared some global variables. In cbm_unit.h I declared a structure with drive properties. In CBM_unit.pas I declared:
    > Device : array[0..coMaxDevice] of ^TEmuDevice;
    >I translated this to:
    > struct EmuDeviceStr Device[coMaxDevice];


    If your Pascal array goes fro 0 to coMaxDevice, then your C array will
    need coMaxDevice+1 entries.

    --
    Remove del for email
    Barry Schwarz, Sep 29, 2013
    #7
  8. Hello Rosario1903,


    > > for (b2 = 0; b1 < 2; b1++)

    >
    > there would be something not ok in that loop


    I already found out in the bad way. But thanks anyway! :)


    Kind regards, Ruud
    Ruud Baltissen, Sep 29, 2013
    #8
  9. Hello Keith, James,


    > > #define CHCSEP '/'

    > Or:
    > enum { chcsep = '/' };


    Thank you very much!


    Kind regards, Ruud
    Ruud Baltissen, Sep 29, 2013
    #9
  10. Hello James,


    > ... and that you haven't inserted a header guard in that file.


    I have:
    #ifndef CBM_UNIT_H_INCLUDED
    #define CBM_UNIT_H_INCLUDED
    ....
    #endif

    Both your and Keith's solution worked fine. But the weird thing, if I ommit the guard, things compile fine as well.
    I have various books about C and C++ but, with one exception, none mentioned the use of header files. So I turned to Google and ran into this:
    http://stackoverflow.com/questions/2831361/how-can-i-create-c-header-files
    http://www.learncpp.com/cpp-tutorial/19-header-files/ and
    http://www.tutorialspoint.com/cprogramming/c_header_files.htm
    And if you check them, they all mention the guard, but none of them mention the use of constants, enums, variables, etc. That's why I'm glad forums exist and more, that there are people willing to answer your questions! :)


    Kind regards, Ruud
    Ruud Baltissen, Sep 29, 2013
    #10
  11. Ruud Baltissen <> writes:

    > Hello James,
    >
    >
    >> ... and that you haven't inserted a header guard in that file.

    >
    > I have:
    > #ifndef CBM_UNIT_H_INCLUDED
    > #define CBM_UNIT_H_INCLUDED
    > ...
    > #endif
    >
    > Both your and Keith's solution worked fine. But the weird thing, if I
    > ommit the guard, things compile fine as well.


    There are lots of things that the compiler can encounter twice without
    causing any problem: function prototypes, certain "extern" declarations
    (those that are not definitions as well), structure declarations and so
    on. One of these is a #define, but a duplicate enum constant (even if
    it has the same value) isn't one. Did a .h file using the enum trick
    really get through multiple includes with no errors?

    <snip>
    --
    Ben.
    Ben Bacarisse, Sep 29, 2013
    #11
    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. =?Utf-8?B?YmJkb2J1ZGR5?=

    different sessions and globals

    =?Utf-8?B?YmJkb2J1ZGR5?=, Aug 15, 2005, in forum: ASP .Net
    Replies:
    2
    Views:
    317
    Kevin Spencer
    Aug 15, 2005
  2. Abhishek Pandey

    static and globals

    Abhishek Pandey, Jan 12, 2005, in forum: C++
    Replies:
    3
    Views:
    568
    Abhishek Pandey
    Jan 13, 2005
  3. David M. Wilson

    Python API, objects, globals, and forking.

    David M. Wilson, Apr 5, 2004, in forum: Python
    Replies:
    0
    Views:
    355
    David M. Wilson
    Apr 5, 2004
  4. Paddy
    Replies:
    6
    Views:
    266
    Kent Johnson
    Feb 24, 2005
  5. Olivier Sessink
    Replies:
    0
    Views:
    381
    Olivier Sessink
    Feb 24, 2005
Loading...

Share This Page