Like Tree8Likes

Macros Queries

This is a discussion on Macros Queries within the C Programming forums, part of the General Programming Boards category; Hello to all. Code: #include <stdio.h> #define CHECK_ZERO(divisor) \ if( divisor == 0) \ printf("**Attempting to divide by zero on ...

  1. #1
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296

    Macros Queries

    Hello to all.

    Code:
    #include <stdio.h>
    #define CHECK_ZERO(divisor) \
    if( divisor == 0)  \
    printf("**Attempting to divide by zero on line: %d " \
    "of file: %s" , ( __LINE__ + 1 ) , __FILE__)
    
    int main( void )
    {
    int x,y;
    
    printf("Give x , y : ");
    scanf("%d%d" , &x , &y);
    
    CHECK_ZERO(x);
    int division = x/y; 
    
    printf("%d" , division);
    		
    return 0;
    }
    The technique ( __LINE__ + 1 ) is good ? Because I want the exact line in which the error will be found.

    Another question is ..... Macro may evaluate its arguments more than once ... but a function only once.... what about if we have

    Code:
    for(int i=0; i<3; i++)
    foo(i) ;
    Each time i will be evaluated .. foo(1) , foo(2) so forth .. why a function evaluates its arguments only once? I don't understand here.... Is there any example of what we mean when we say that a macro may evaluate its arguments more than once ?

    Thank you in advance.

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    1,625
    Macros are just replacing sequences, eg Whatever you place between the parenthesis will be copied everywhere the argument name appears. The values of function argument expressions on the other hand are pre-calculated.
    Mr.Lnx likes this.
    Devoted my life to programming...

  3. #3
    Registered User
    Join Date
    Jun 2005
    Posts
    6,426
    Quote Originally Posted by Mr.Lnx View Post
    Code:
    CHECK_ZERO(x);
    int division = x/y;
    The technique ( __LINE__ + 1 ) is good ? Because I want the exact line in which the error will be found.
    The nature of the macro is that you clearly use it to check if its argument is zero before the next line that actually does the division.

    Personally, I think it is sloppy, as the macro can be used anywhere, including in places where it isn't followed by a division. Others may disagree.

    Quote Originally Posted by Mr.Lnx View Post
    Another question is ..... Macro may evaluate its arguments more than once ... but a function only once.... what about if we have

    Code:
    for(int i=0; i<3; i++)
    foo(i) ;
    Each time i will be evaluated .. foo(1) , foo(2) so forth .. why a function evaluates its arguments only once? I don't understand here.... Is there any example of what we mean when we say that a macro may evaluate its arguments more than once ?
    The example you gave isn't relevant to a macro evaluating its arguments twice. The thing to remember is that macros do text substitution. The compiler then sees the expression after text substitution has occurred.

    So, you could implement a macro called Foo, like
    Code:
    #define Foo(x)   (x) + (x)
    or your could define an function (inline if desired) to do what superficially appears to be the same thing
    Code:
    int Foo(int x) {return (x) + (x);}
    Now, let's say we have a main() function that does this
    Code:
    int main()
    {
         int y = 2;
         int z;
    
         z = Foo(y++);
         /* print values of y and z here */
    }
    The results will be different depending on whether the compiler has visibility of the macro or the function version of Foo().

    With the macro version of Foo(), the compiler will see the line "z = Foo(y++;)" as "z = ((y++) + (y++));". That increments y twice in one statement, so gives undefined behaviour - which means the C standard gives no guarantee whatsoever about the results of doing this. The values of y and z, after this statement, can vary between compilers, can change over time, and can even change between versions of a compiler. The program is even permitted to crash, reformat your hard drive, or anything else.

    With the function version of Foo(), the result is 100% predictable. y will be evaluated with the value 2, Foo(2) will be called, y will be incremented exactly once. So z will receive the value of 4, and y will end up with a value of 3. That is guaranteed.

    Things are even worse if both the macro version and the function version of Foo() are supplied in one source file.
    Last edited by grumpy; 03-03-2013 at 03:22 AM. Reason: Remove accidential smileys
    Mr.Lnx and jwroblewski44 like this.
    Right 98% of the time, and don't care about the other 3%.

  4. #4
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296
    Thank you very much all for the answers.

    Grumpy your explanation is great. I am ok. I think you have a little mistake though....

    Code:
    the compiler will see the line "z = Foo(y++;)"
    You may want to put the ; at the end of the statement ..... z = Foo(y++);

    Another issue... Do you have a good and simple example about #line directive?????

    Thank you in advance.

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    6,426
    Quote Originally Posted by Mr.Lnx View Post
    the compiler will see the line "z = Foo(y++" You may want to put the ; at the end of the statement ..... z = Foo(y++);
    Yes, indeed. A typo in my post. I can't go back and edit it now though.

    Quote Originally Posted by Mr.Lnx View Post
    Another issue... Do you have a good and simple example about #line directive?????
    Any simple example I would give would come from compiler documentation.

    MSDN have a description, here. gcc online docs also have a discussion here.

    The real (and more complex) examples I've seen in practice are along the lines of a parser program that takes some input file, and generates C or C++ source code. The #line directive is used in the generated source code so, if errors are encountered executing that code, line numbers in the original input file are reported (a line number in the generated source would not be informative). The gcc online docs hints at this type of example by its references to bison (bison is a parser generator - it reads a specification of a parser, and outputs C code to implement that parser). Until the 2004 or so (IIRC) a bison-generated parser was a central part of all working compilers in the GNU compiler collection.
    Right 98% of the time, and don't care about the other 3%.

  6. #6
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296
    Somewhere I read that __LINE__ gives the current number of the line which is the number of new line characters plus 1. #'\n' + 1.

    But I cannot understand here why we take 6 and not 7.

    Code:
    #include<stdio.h>
    #line 2 
    
    int main(void)
    {
    	
    	printf("This is line %d" , __LINE__);
    
    return 0;
    }
    Also what we mean with "rescanning" ?

    For example

    Code:
    #undef sqrt 
    #define sqrt(x) ((x) >= 0 ? sqrt(x) : 0 )
    A later call of sqrt will be intercepted by the preprocessor , which expands it into the conditional expression shown here.The call of sqrt inside the conditional expression won't be replaced during rescanning so it will remain for the compiler to handle

    The truth is that I face some unexpected problems while I am reading this chapter .... I haven't had the same difficulties from previous chapters maybe my questions are ridiculous and I apologize for that. Thank you in advance

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    6,426
    #line specifies the number that should be reported for the NEXT line of input.

    Rescanning means that, after a macro has been expanded, it is rescanned (i.e. scanned again) to look for more macro names to expand. If the name of the macro being expanded is found in that process (i.e. the macro is self-referential) it is not expanded further. Among other things, this prevents infinite loops with macro expansion (or the macro expansion equivalent of infinite recursion) of the form "macro expands to itself which expands to itself ..... ".
    Mr.Lnx likes this.
    Right 98% of the time, and don't care about the other 3%.

  8. #8
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296
    Quote Originally Posted by grumpy View Post
    #line specifies the number that should be reported for the NEXT line of input.

    Rescanning means that, after a macro has been expanded, it is rescanned (i.e. scanned again) to look for more macro names to expand. If the name of the macro being expanded is found in that process (i.e. the macro is self-referential) it is not expanded further. Among other things, this prevents infinite loops with macro expansion (or the macro expansion equivalent of infinite recursion) of the form "macro expands to itself which expands to itself ..... ".
    You mean something like that :

    Code:
    #include<stdio.h>
    #define average(x) x/2
    #define sum_of_average(x)  average(x) + average(x)
    #line 2 
    
    int main(void)
    {
    	
    	int y=8;
    	
    	printf("%d\n" , sum_of_average(y));  // 8/2 + 4 = 8 not 8/2 + 4/2 = 6
    
    return 0;
    }
    Last edited by Mr.Lnx; 03-10-2013 at 10:56 AM.

  9. #9
    Registered User
    Join Date
    Jun 2005
    Posts
    6,426
    No. Your example is simply one macro expanding to another.

    And, contrary to your comments, the compiler will see the printf() statement as
    Code:
         printf("%d\n" , y/2 + y/2);
    I mean things like
    Code:
    #define foo foo
    or
    Code:
    #define A (2*B)
    #define B (A + 1)
    Mr.Lnx likes this.
    Right 98% of the time, and don't care about the other 3%.

  10. #10
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296
    Hello again... I kept this thread about queries for macros... I have some last (I hope) queries .....

    I don't know if they are important though ... let's start :

    Code:
    #include<stdio.h>
    #define ONE 1 
    #define TWO (ONE+ONE)
    #define THREE (ONE+TWO)
    
    int main(void)
    {
    	
    	TWO;
    	THREE;
    
    return 0;
    }
    With -E flag of gcc i take the output of the preprocessor so I take :

    Code:
     
    
     (1 +1);
     (1 +(1 +1));
    At the point of the calls TWO and THREE respectively , why there is a gap between (1 +1) ?

    ....

    Secondly

    Code:
    #include<stdio.h>
    #define GENERIC_MAX(type)      \
    type type##_max(type x, type y) \
    {                               \
         return x > y ? x : y;      \
    }
     
    int main(void)
    {
    	
    	GENERIC_MAX(float);
    	
    	return 0;
    }
    I take an error :

    Code:
     tests.cpp:11: error: a function-definition is not allowed here before ‘{’ token
    We should put the call of macro outside the main????

    In addition when I was called the GENERIC_MAX with GENERIC_MAX(unsigned long) I took an error "duplicate" I know why... but when I was called with long int I didn't take an error.... by chance? Because long int has two words as unsigned long which is the basic problem for the labeled error "duplicate" ....
    Last edited by Mr.Lnx; 03-18-2013 at 07:19 AM.

  11. #11
    Registered User
    Join Date
    Jun 2005
    Posts
    6,426
    Quote Originally Posted by Mr.Lnx View Post
    At the point of the calls TWO and THREE respectively , why there is a gap between (1 +1) ?
    If you look at your example, the presence of whitespace makes no difference to the meaning of the preprocessed code (the results of compilation will be the same, regardless of whether the whitespace is present). The standard explicitly allows a preprocessor to insert additional whitespace in circumstances where it makes no difference. (Well ... the wording in the standard is not quite that, but that is the effect in this case).

    Quote Originally Posted by Mr.Lnx View Post
    I take an error :

    Code:
     tests.cpp:11: error: a function-definition is not allowed here before ‘{’ token
    I can't understand why... I didn't take this error yesterday with the same code....
    You're forgetting that the preprocessor does text substitution, and its output is source code which is subsequently compiled.

    Using your GENERIC_MAX() function creates a function definition (i.e. implementation of a function).

    Nested functions (functions implemented in the bodies of other functions) are illegal in C. The only way your macro can be used is at file scope (i.e. not within the body of any function).

    Quote Originally Posted by Mr.Lnx View Post
    In addition when I was called the GENERIC_MAX with GENERIC_MAX(unsigned long) I took an error "duplicate" I know why... but when I was called with long int I didn't take an error.... by chance? Because long int has two words as unsigned long which is the basic problem for the labeled error "duplicate" ....
    That macro is creating a function definition. If you use it twice, with exactly the same parameter, it will create two identical function definitions.

    That runs afoul of a rule in the C standard, known colloquially as the "one definition rule", which says no function may be defined more than once in a complete program. (There are other definitions that are also only permitted once, not just function definitions).

    A C compiler will complain if a particular source file (after preprocessing) contains two definitions of one function. If the two distinct definitions are in separate source files (after preprocessing of each) then the compiler won't usually complain (as source files are compiled separately) but the linker usually will when it encounters the same function defined in two distinct object files. Whether it is the compiler or linker that complains, you are running afoul of the one definition rule.
    Right 98% of the time, and don't care about the other 3%.

  12. #12
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by Mr.Lnx View Post
    In addition when I was called the GENERIC_MAX with GENERIC_MAX(unsigned long) I took an error "duplicate" I know why... but when I was called with long int I didn't take an error.... by chance? Because long int has two words as unsigned long which is the basic problem for the labeled error "duplicate" ....
    Code:
    GENERIC_MAX(long int)
    expands to
    Code:
    long int long int_max(long int x, long int y) ...
    and "long int long" is a legal type in C99 (type specifiers can be written in any order: "long long int" is equal to "int long long" and "long int long")

    The other way round
    Code:
    GENERIC_MAX(int long)
    expands to
    Code:
    int long int long_max(int long x, int long y)
    and won't work because "int long int" is not a legal type.

    Bye, Andreas

  13. #13
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296
    However I don't take an error with real function instead of a macro as we said before

    Code:
    #include<stdio.h>
    int main(void)
    {
    	
    	int f1(int x , int y)
    	{
    		return x > y ? x : y;
    	}
    	
    	printf("The biggest is : %d" , f1(2 , 4));
    	
    return 0;
    }
    It works by chance???

    Anyway

    Let's fix the previous problem with macro ...

    Code:
    #include<stdio.h>
    #define GENERIC_MAX(type)      \
    type type##_max(type x, type y) \
    {                               \
         return x > y ? x : y;      \
    }
     
    int main(void)
    {
    	
    	return 0;
    }
    GENERIC_MAX(signed int);
    GENERIC_MAX(long int);
    GENERIC_MAX(unsigned long);
    My question now is why I take 2 errors and not 3 errors.

    Code:
      tests.cpp:13: error: duplicate ‘signed’
    Code:
     tests.cpp:15: error: duplicate ‘unsigned’
    long int parameter has 2 words.... the expansion would be :

    Code:
    signed int signed int_max(signed int x, signed int y) { return x > y ? x : y; };
    long int long int_max(long int x, long int y) { return x > y ? x : y; };
    unsigned long unsigned long_max(unsigned long x, unsigned long y) { return x > y ? x : y; };
    long int long int_max ???? why does not produce an error (which is based that the type consist of two reserved words not only one for example int or float or something like that).

    Thank you very much for the detailed answers
    Last edited by Mr.Lnx; 03-18-2013 at 09:37 AM.

  14. #14
    Registered User
    Join Date
    May 2012
    Posts
    1,066
    Quote Originally Posted by Mr.Lnx View Post
    However I don't take an error with real function instead of a macro as we said before

    It works by chance???
    Nothing works by chance in programming :-)
    Nested functions are an extension of some compilers, e.g. gcc. (The gcc page is down at the moment so I can't provide a link to the online docs)
    If you compile your code with gcc and use the "-pedantic" option, you get the expected error:
    Code:
    $ gcc -o foo -pedantic foo.c
    foo.c: In function ‘main’:
    foo.c:5:5: warning: ISO C forbids nested functions [-pedantic]
    Quote Originally Posted by Mr.Lnx View Post
    long int parameter has 2 words.... the expansion would be :
    Code:
    long int long int_max(long int x, long int y) { return x > y ? x : y; };
    long int long int_max ???? why does not produce an error (which is based that the type consist of two reserved words not only one for example int or float or something like that).
    What compiler are you using?
    It looks like your compiler accepts the C99 standard and I've explained the behaviour already in post #12.

    Bye, Andreas

  15. #15
    Registered User
    Join Date
    Sep 2011
    Location
    Athens , Greece
    Posts
    296
    I was confusing because the solution said

    (b) The problem with types such as unsigned long is that they require two words, which prevents GENERIC_MAX from creating the desired function name.

    So I didn't think more widely...... Hence unsigned long unsigned is not legal type in C99.
    Where Can I find the legal types??? thank you.
    Last edited by Mr.Lnx; 03-18-2013 at 12:38 PM.

Page 1 of 2 12 LastLast
Popular pages Recent additions subscribe to a feed

Similar Threads

  1. some queries on arrays
    By jackson6612 in forum C++ Programming
    Replies: 9
    Last Post: 06-22-2011, 04:33 AM
  2. two small queries
    By jackson6612 in forum C++ Programming
    Replies: 2
    Last Post: 05-27-2011, 04:30 AM
  3. Macros inside of macros
    By Chewie8 in forum C Programming
    Replies: 2
    Last Post: 02-24-2008, 02:51 AM
  4. DLL Making and Symbols - 2 Queries
    By Tronic in forum C++ Programming
    Replies: 9
    Last Post: 12-31-2004, 12:11 AM
  5. text file queries
    By ozzy34 in forum C++ Programming
    Replies: 2
    Last Post: 09-30-2004, 10:42 AM

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21