This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

what's thie meaning for "#ifndef __C51__"

In Keil demos, I find some definitions such as "#ifndef __C51__", what's the meaning for double '_'.

Parents
  • As opposed to Pascal language, C language suffers from the lack of name spaces. There is no way in to import resources from a module in C/C++, the file is included as a whole. As a result, if you include modules A and B, whereas module B uses module A, you have a redifinitions and other conflicts. In other words, the global scope is a big mess. #ifndefs in H files solve this problem paritally. Returning to example, module A is included only once wrapped into #ifndef condition.
    It is widely adopted in C programming to use module names as identificators with double subscribts. For example,
    #ifndef __moduleA_H__
    #define __moduleA_H__
    // this H file will be included only once
    //definitions here
    #endif

Reply
  • As opposed to Pascal language, C language suffers from the lack of name spaces. There is no way in to import resources from a module in C/C++, the file is included as a whole. As a result, if you include modules A and B, whereas module B uses module A, you have a redifinitions and other conflicts. In other words, the global scope is a big mess. #ifndefs in H files solve this problem paritally. Returning to example, module A is included only once wrapped into #ifndef condition.
    It is widely adopted in C programming to use module names as identificators with double subscribts. For example,
    #ifndef __moduleA_H__
    #define __moduleA_H__
    // this H file will be included only once
    //definitions here
    #endif

Children
  • Pascal has just as little namespace protection as C, unless I remember some things very incorrectly.

    As to the "code uses module B, which in turn needs module A" scenario: you're wrong. Properly written C headers can very well #include other headers, without causing any double definition problems, for two reasons:

    1) Multiple inclusion guards, as you mention.

    2) There should never be any definition in a header file, to begin with, and thus it can't collide with any in some other header file. Only declarations go on there.

    And no, names starting with double _ are *not* correct C. If they're widely adopted, that would make them a very common error.

    Your own code (unless you're a compiler or runtime library implementor) should use

    #ifndef MYPROGRAM_FILE_H
    #define MYPROGRAM_FILE_H
    // all actual declarations in here..
    #endif

    or some similar scheme, instead.

  • we have strayed from the original question...

    "2) There should never be any definition in a header file"

    Just to clarify, that means code or data definitions; type definitions and preprocessor #defines are good in headers.

  • Typically all my C programs are one file length. I create H/C couple only for reusing among different programs. Therefore, this structure

    #ifndef MYPROGRAM_FILE_H
    #define MYPROGRAM_FILE_H
    // all actual declarations in here..
    #endif
    
    is not for me.

    I don't know the difference between definition and declaration but compiler does not allow me to declare a variable in H file. All I can do in H file is to define a type and predefine a function. 90% of my average H file are definitions of constants.
    May be this dispute is out of scope of this article but I know that a Pascal's comiler looks for an element in the imported unit only if it cannot find the definition in the current module. This separates scopes of the modules increasing compilation times thousands of times.

  • I don't know the difference between definition and declaration but compiler does not allow me to declare a variable in H file
    HUH?

    I do it all over, having #defines such as

    #ifdef main
    #define U8 unsigned char
    #else
    #define U8 extern unsigned char
    #endif
    
    U8 hello;

    erik

  • Erik,

    Placing the defining declaration in a header file is precisely what the other replies to this thread have explained is bad practice. Strangely enough, it makes code very difficult to maintain.

    Stefan

  • Some points need clarification here, I think:

    *) Even in a single-source-file project, you should make it a habit to always have multiple-inclusion guards on your header files. Never write any .h file without one --- odds are it'll save your day years later, even if it's not actually needed right now.

    *) You say: "I don't know the difference between definition and declaration". That's exactly the reason you're having problems with header files. To declare a variable in a header file, write:

    extern type_name variable_name;

    The extern is the crucial part, here. Without it, the same line is a (tentative) definition, which gets you exactly those multiple definition complaints from the linker you mentioned.

    *) You mentioned "extern imports" in your .c files --- those are symptoms of the exact same trouble. As a rule of thumb, "extern" should never appear inside a .c file. Each time it does, you really should have #include'd a header file instead.

    *) As to Pascal's name resolution policy: that comes nowhere close to what "namespaces" really should be. Look at C++ for a better idea. Following your description, Pascal would only support two namespaces: "here" and "elsewhere", with no way to access an object in "elsewhere" once you've defined one of the same name "here".

  • "I don't know the difference between definition and declaration"

    Read K&R, and see this thread:
    http://www.keil.com/forum/docs/thread1847.asp

    Basically, a definition creates code and/or data; a declaration merely informs the compiler about code and/or data.

    Therefore, declarations are good in headers; definitions are bad!

    "compiler does not allow me to declare a variable in H file"

    Nonsense!
    The compiler doesn't care - it will let you have both definitions and declarations in headers.

    If you get errors when you declare (or, more likely, define) a variable in a Header file, it has nothing to do with the fact that it's in a header file per se; more likely you are falling into one of the pitfalls which is why we say: don't define code or data in headers!

  • Standard Pascal does not allow for separate compilation at all, so the issue of modules and name spaces does not arise. Real-world useful Pascal implementations (say, Borland's Turbo Pascal) added their own language mechanisms to support separate compilation, none of which are necessarily compatible. So it's hard to say anything meaningful about what "Pascal" does with namespaces.

    I favor the practice of using a .h file as a "declarations" file only. Put in the internal #include guards. Some compilers will track the #include nesting and avoid re-including a file anyway, but it's best to be sure. Putting in the actual definitions (space-reserving, as opposed to extern references) tends to lead to trouble.

    There are occasional other header file tricks, usually redefining a macro in two different ways to produce two different bits of C syntax when included from different contexts. (See, for example, Bob Horeck's comment and use of TxtItem in the thread http://www.keil.com/forum/docs/thread2785.asp. The authors of the OSE RTOS are also fond of this trick for implementing their configuration files.) This sort of thing is, in my opinion, best kept well separated from your "normal" header files to avoid confusion.

    There's use of the #include mechanism to emulate module export / linkage mechanisms that ought to have been built into the language proper, which is a near-universal C programmer convention; and then there's use of the preprocessor just as a text macro processor not necessarily having anything to do with C.