Kiran Divakaran <kiran_divaka...@...> wrote:
> Brett McCoy wrote:
> > <kiran_divaka...@...> wrote:
> > > I have a query with #defines in C.
> > >
> > > There is a -E compiler option which would expand the
> > > #define at compile time and create an intermediate file
> > > and create the object file for the same.
> > >
> > > But normally do #defines get expanded at compile time
> > > or at run time.
> > 
> > Pre-processor directives technically are handled even
> > before the compile stage, they get expanded by the pre-
> > processor before the code is compiled.

Technically, there are 8 Translation Phases, roughly described
as:

  1) Source character mapping and trigraph replacement.
  2) Line splicing (trailing \) resolved
  3) Parsing to preprocessor tokens, comments become spaces.
  4) Macros expanded and preprocessor directives expanded
  5) Mapping of source characters to execution character set
  6) Adjacent string literals are concatenated
  7) Whitespace is removed and preprocessing tokens are
       converted to tokens and parsed syntactically and
       semantically.
  8) External function references are resolved and a program
       'image' is created.

A conforming implementation must behave as if it performs
these steps. C is generally a compiled language, but there
are, or at least have been, C interpreters. But in compiled
form, the phases are generally mapped as:

  TP1-4 Preprocessing
  TP5-7 Compilation
  TP8   Linking

> > By the time the code is compiled, no traces of the
> > original pre-processor directives are left behind.

Even before the code is compiled, no traces of pre-
processing tokens or directives are left.

> > Run gcc with the -E option
> > and you will see what the pre-processed code looks like

Not precisely. Preprocessors output preprocessing tokens.
When asked to display those tokens most preprocessors will
generally produce a text file that will be re-parsed the
same way. But there may be cases when it won't be precisely
the same. For instance, most preprocessors will not preserve
pragma directives (e.g. struct packing.)

> >  -- you will see the contents of, say, stdio.h included
> > in the output and all of the #defined macros expanded.
>
> If this is the case. Then there is another query .
> 
> While defining macros compiler support different styles of
> macros namely C9X and GNU style macros.
> 
> Suppose a code is compiled for GNU style and an object file
> of the same is created, will this later work on a C95 style
> supported compiler.

Compilation is just one part of the translation phases. An
implementation is _all_ the phases. If you compile different
source files (translation units) in different languages, or
even the same compiler but with different compiler options,
then there's no immediate guarantee that you can link object
files.

> This anyways will be at runtime but since already the sense
> of the #define is made at compile time , will there be any
> issues of portability ?

Whenever you use non-standard extensions you sacrifice a bit
of portability. Sometimes that's justifiable, sometimes it
isn't.

> When this code is run on a machine which say is upgraded
> to the higher version of the compiler which perhaps supports
> only one style of the macro version.
> 
> http://www.docs.hp.com/en/5969-4407/ch01s01.html
> 
> C9X
> 
> GNU
> 
> #define foo(f, ...) printf (f, __VA_ARGS__)
> 
> #define foo(f, s...) printf (f, s)
> 
> What would happen will the same code run? It should if the
> object binaries are compatible across the upgraded compiler.
> I have perhaps answered the question ? But is that the case ?

You'll have to check the implementation documentation to know
if the object files are compatible. A bigger question is whether
this is the only GNU extension you're using. That will likely
be a bigger issue.

Variadic macros are problematic in that not all C90 compilers
support them as extensions. If they do, it's not necessarily
the case that they support the C9X semantics. As you've
observed, GNU's gcc has it's own version.

I'm not sure what your use for foo is. By far the most common
use is debug logs, printing a message to stderr. For that, I
use a C90 compatible trick along the lines of...

  int debugf_(const char *, ...);
  #ifndef NDEBUG
  #define debug   if (0) ; else
  #define debugf  debugf_
  #else
  #define debug   while (0)
  #define debugf  (void)
  #endif

Thus, I can do code like (contrived sample)...

  int foo(int x)
  {
    debugf("foo(%d)\n", x);
    debug
    {
      int y = x * x;
      debugf("foo: x = %d, y = %d\n", x, y);
    }
    return x + 42;
  }

Since debugf_ is a variadic function, debugf mimics a variadic
macro for most intents and purposes. Using variadic function
wrappers is more portable that attempting to use preprocessor
tricks.

-- 
Peter

Reply via email to