tags:

views:

337

answers:

4

I'm going through the source code of the "less" unix tool by Mark Nudelman, and the beginning of main.c has many of the following:

public int  logfile = -1;
public int  force_logfile = FALSE;
public char *   namelogfile = NULL;

etc. in the global scope, before the definition of main(),

What does public mean in this context? And more important, where can I find this information by myself? I searched using countless query combinations, and could not find this information, or any thorough C reference.

+1  A: 

C doesn't have a keyword "public", so it's probably a macro defined in the less source code somewhere.

sepp2k
+20  A: 

In the file less.h is your answer:

#define public  /* PUBLIC FUNCTION */

It seems like public is only used as a marker for public/global functions and variables. When compiled, it is expanded to nothing.

How to find this information?

  1. Search the .c file from top to the location of the identifier you want more information about
  2. If you do not find any declaration, look for #include directives
  3. Open any included file and look for the declaration of what you are looking for
  4. Repeat from step two for every included file

In this case, that was pretty simple.

Timbo
Nice find :-) I was too lazy to find the source somewhere and look for myself :-)
Joey
Amazing find, thanks!My lesson as a programmer from this is not to call such things in words that will appear to be part of the language and not part of my code :)
Tzafrir
Just to add my thoughts on the issue if you ever think of doing something like this in your own code... I really don't like #define's like this that try to look like keywords in the source code but just vanish in preprocessing, since it leads to confusion for readers (this very question is proof of that!). Personally I think all #define'd constants/macros should be ALL_UPPER_CASE for clarity/consistency.
David Claridge
If the same code has to be built into a shared library on Windows and also work on Unix, then you have to get into shenanigans to deal with the MS declspec stuff. GCC seems to handle some of it anyway (not chased through in detail), but not every compiler does. Also, to find such definitions, a tool such as `cscope` (http://cscope.sourceforge.net/) can help - or a more powerful IDE.
Jonathan Leffler
+2  A: 

The definition of public as an empty pre-processor macro has been addressed in other answers. To find the definition, you probably want to use a tool like ctags/etags or cscope. (There are many tools to scan a source tree to generate this information.) For example, you can find the definition of public at line 55 of less.h by invoking:

$ ctags -dtw *.c *.h
$ vi -t public

Or, simply run ctags before you start editing anything. When you see a definition you don't understand, put the cursor on it and type ^] (that's control-right square bracket, and will work in vi-like editors.)

William Pursell
Note that the option to ctags may vary. With exuberant ctags no options are necessary, but some forms of ctags require the -d option to emit tags for pre-processor macros without arguments. -t will emit tags for typedefs, and -w is just to suppress various warnings.
William Pursell
+4  A: 

This has nothing to do with C as such. If you look in the include file less.h you will see that the author has defined a number of preprocessor instructions. Some of them like 'public' is most likely for readability. E.g.:

 /*
 * Language details.
 */
#if HAVE_VOID
#define VOID_POINTER void *
#else
#define VOID_POINTER char *
#define void  int
#endif
#if HAVE_CONST
#define constant const
#else
#define constant
#endif

#define public  /* PUBLIC FUNCTION */

See how public is defined. It's translated to nothing and as you have already figured out it's in the global scope. However it's more readable and more obious that it's in the global scope. Also, one could argue that if the source is written consistently like this and a new version of C emerges that does have a public keyword, it's a matter of redefining the the header file and recompile to actually use it.

Preprocessing tricks like this can even be used in clever ways to have one source compile in different languages (like C++ and Java). This is not something you should be doing, but it's possible to it.

The options like HAVE_VOID you see in the example from less.h above are usually specified as compiler (actually preprocessor) options on compile time. So if you have a compiler and a version of C that supports the void keyword you would compile your source with:

g++ -g -DHAVE_VOID -Wall myprog.C -o myprog

Everywhere the author uses VOID_POINTER in the source would then actually be considered by the compiler as:

void *

If you didn't specify HAVE_VOID the compiler would instead use

char *

which is a reasonable substitue.

TIP: Check your compiler's options to see if you have an option to just preprocess your sources. That way you can look at the actual source that gets sent to the compiler.

danglund
Yes, I'm quite familiar with gcc -E
Tzafrir