Test bounds macro in C will not work

Hi, I wrote a test macro to check when I went beyond the bounds of an array vs. writing the same test over and over again but gcc will not accept it. Here’s an over simplified version that exhibits the bug.


#define TESTME(pos, maxpos) ((pos) <= (maxpos)) ? : return(0);

int main(void)
{
    int a = 0;
    int b = 100;
    while(a++)
    {
        TESTME(a, b);
    }
    
    return(0);
}


% gcc a.c
a.c: In function ‘main’:
a.c:1:53: error: expected expression before ‘return’
 #define TESTME(pos, maxpos) ((pos) <= (maxpos)) ? : return(0);
                                                     ^
a.c:9:9: note: in expansion of macro ‘TESTME’
         TESTME(a, b);
         ^

If I code it with an if test then it will compile. I’m not understanding why the ? : construct does not do the job. To me the ? : construct makes a prettier one liner and even if I were to just decide that the if was ok I still want to know what makes the? : unacceptable as I desire to understand the language better and better.

On 2014-06-13, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
> Code:
> --------------------
> #define TESTME(pos, maxpos) ((pos) <= (maxpos)) ? : return(0);
> --------------------

Don’t confuse functions with macros. Non-void functions return a value, whereas macros do not. Macros merely expand code
according to what you’ve written inside and are in themselves not a function. You could just delete eveything from `?’
onwards and it will probably compile fine.

If I code it with an if test then it will compile. I’m not understanding
why the ? : construct does not do the job. To me the ? : construct makes
a prettier one liner and even if I were to just decide that the if was
ok I still want to know what makes the? : unacceptable as I desire to
understand the language better and better.

The `? :’ construct is the ternary operator, and its use is not confined to macros (indeed it can be very poor
programming style to use ternary operators inside macros). Ternary allows the value of any variable to be assigned
depending the truth value of another and potentially otherwise unrelated variable:


result = condition ? trueValue : falseValue

for example,


int x = 10;
int isEven = x % 2 ? 0 : 1;

…although this of course can replaced by the more elegant !(x % 2)).

If the trueValue is missing (an obscure C extension), then the condition is used to replace it. In other words, the
following are equivalent:


result = condition ? condition : falseValue
result = condition ? : falseValue

Btw, I imagine you are aware that the contents of your while loop will never run in your main function…

int main(void)
{
int a = 0;
int b = 100;
while(a++)
{
TESTME(a, b);
printf("%d
", a);
}

…since you’ve used the post-increment (a++) but `a’ starts at a=0.

I just created the code quickly, it was never supposed to run.
I thought that macros were expanded by cpp and so never actually returned anything. This makes lots of duplicate code be able to be expressed in a single statement, that would be: TESTME
Undoubtedly, you are about to recommend a function or some other method of avoiding duplication. I think that the testme macro, as it is the real thing, demonstrates that it is to small to be worth putting in a function (unless the function is to be labeled inline but let’s not get into such matters,) and it is impractical to use less tests as the code I’m writing is using re2c and that means I’m writing a lexical analyzer for speed. If you look at the examples you will note that it is impractical to put the test into the loop.
But back to our original question, what’s the difference from writing the ternary operator in the macro vs. in the function’s body itself since the macro gets expanded into the function anyway.
“You could just delete everything from ‘?’ onwards and it will probably compile fine.”
Your right, and that’s what’s so confusing about the whole thing. You could substitute the macro in by hand and it still would not compile, so what is the ternary operator that it can’t accept return. An why does this work?

#define TESTME(pos, maxpos) ((pos) <= (maxpos)) ? : pos++; return(0);

After all it’s just 2 commands instead of one following the ternary operator.
“Ternary allows the value of any variable to be assigned
depending the truth value of another and potentially otherwise unrelated variable”
I lost something here, assigned to what and where is the assignment and what value is being assigned? The variable that follows the resulting truth or false value?

On 2014-06-13, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
> I just created the code quickly, it was never supposed to run.

Ahh. OK.

On 2014-06-13, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
> I thought that macros were expanded by cpp and so never -actually-
> returned anything.

I’m confused. You were referring to C in your original post (with C code) and now you are referring to CPP. If you
compiling `gcc a.c’, then that’s C and has nothing to do with CPP/C++.

This makes lots of duplicate code be able to be
expressed in a single statement, that would be: TESTME
Undoubtedly, you are about to recommend a function or some other method
of avoiding duplication.

Not necessarily. If you’re really using C++, and want index bounds checking on arrays, then I strongly suggest you use
C++'s containers (e.g. vectors or deques) rather than constructing your own methods. They are going to be more efficient
than anything you write, unless you are happy to code in inline assembler (which I do).

I think that the testme macro, as it is the
real thing, demonstrates that it is to small to be worth putting in a
function (unless the function is to be labeled inline but let’s not get
into such matters,)

This is a perfectly legitimate case for using an inline function so why not use one?

and it is impractical to use less tests as the code
I’m writing is using re2c and that means I’m writing a lexical analyzer
for speed. If you look at the examples you will note that it is
impractical to put the test into the loop.

If you are coding in C++ rather than C, then I strongly suggest you read Agner Fog’s guide of optimising C++.

But back to our original question, what’s the difference from writing
the ternary operator in the macro vs. in the function’s body itself
since the macro gets expanded into the function anyway.

Nothing. But you may want to know the result of the ternary condition for more than just the reason of the assignment of
a single variable. Repeated use of the same macro will mean the generated assembler will evaluate in full (i.e. test the
condition) every time it is called, even if the code logic dictates the same result every time. This is inefficient.

“You could just delete everything from ‘?’ onwards and it will probably
compile fine.”
Your right, and that’s what’s so confusing about the whole thing. You
could substitute the macro in by hand and it still would not compile, so
what is the ternary operator that it can’t accept return.

…because your falseValue of the ternary operation is `return(0)’ which is wrong and should generate an error.

> An why does this work?
>
> Code:
> --------------------
> #define TESTME(pos, maxpos) ((pos) <= (maxpos)) ? : pos++; return(0);
> --------------------

This works because the falseValue of the ternary operation is pos++'. The return(0)’ has absolutely nothing to do with
the ternary operation (it’s after a `;’ which delimits the end of the ternary operation) and all it will do is make the
function return every time you use the macro. C

After all it’s just 2 commands instead of one following the ternary
operator.

Consider this code, using the macro definition for TESTME you’ve written above:


#include <stdio.h>
#define TESTME(pos, maxpos) ((pos) <= (maxpos)) ? : pos; return(0);

int main(void)
{
int a = 0;
int b = 100;
int isEven = b % 2 ? 0 : 1;
isEven = !(b % 2);
TESTME(a, b);
while(a++)
{
TESTME(a, b);
printf("%d
", a);
}

printf("%d
", a);
return(0);
}

Now when I run the code (save as a.c), this is the result…


sh-4.2$ gcc a.c
sh-4.2$ ./a.out
sh-4.2$

…i.e. nothing. All you’ve done with macro is make the main() function return the first time you call TESTME: this has
nothing to do with the ternary operator.

“Ternary allows the value of any variable to be assigned
depending the truth value of another and potentially otherwise unrelated
variable”
I lost something here, assigned to what and where is the assignment and
what value is being assigned? The variable that follows the resulting
truth or false value?

If you’re lost, you need to start at the beginning and learn the fundamental properties of ternary operators. The topic
is completely independent of the use of macros. Ternary operations are identical to inline if' operations. It would be helpful if you could clear if you're learning C or C++. The reason for the need for the distinction is that standard C (until C99, and even then it's an odd implementation) does _not_ support the bool’ datatype whereas C++ does. I thought
my `isEven’ example was clear, but it seems you are still lost. If you are learning C++, it could show a clearer
example.

I’m learning C99. I never have found any information aside from the syntax definition of the ternary operator as to why to use it or why it was created (which is probably why I’m so lost. So, please forgive the naivety.)
Kindly don’t mention to RTFD I’ve researched C more thoroughly then anything else I can imagine. The only things I have yet to finish reading are the recommendations from the group in charge of the development of C99 (which are proving very insightful but also very dull.)
I thought that, like an if statement, the ternary operator could take multiple commands like this:


(a >= b) ? command1; command2; : command3; command4;

But, like I said, I was only ever told that the ternary operator was there, not what it’s intended use is. So, by all means point me to the docs on the subject and I shall read them.
You think it would be better inline? Ok, I thought that it was better as a macro, but you have more experience then I. One question though, does an inline function’s return statement get removed when it is placed inline since having a return in an inline function would cause the caller to return?

On 2014-06-23, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
> I’m learning C99. I never have found any information aside from the
> syntax definition of the ternary operator as to why to use it or why it
> was created (which is probably why I’m so lost. So, please forgive the
> naivety.)

There is no situation in which the only way to implement C/C++ code is using the ternary operator. If in doubt, use
if {} else {}; if you’re using a reasonable compiler, the ternary operatory in no way improves performance. The main
advantage of the ternary operator is that it can make some code easier to read.

> Kindly don’t mention to RTFD I’ve researched C more thoroughly then
> anything else I can imagine. The only things I have yet to finish
> reading are the recommendations from the group in charge of the
> development of C99 (which are proving very insightful but also very
> dull.)
> I thought that, like an if statement, the ternary operator could take
> multiple commands like this:
>
> Code:
> --------------------
>
> (a >= b) ? command1; command2; : command3; command4;
>
> --------------------

… the `if’ usage is a conditional branch statement not an operator, and therefore will accept concatenated
instructions separated by semi-colons within braced code blocks. The ternary operator is an operator (like + or -)
except requires two characters (i.e. ? and :slight_smile: rather than one with three operands (or two if leaving the trueValue
blank).

But, like I said, I was only ever told that the ternary operator was
there, not what it’s intended use is. So, by all means point me to the
docs on the subject and I shall read them.

If you can’t think of a use of the ternary operator don’t use it. Apart from improving code-readability in certain
cases, it gives you no additional benefit over if {} else {} sequences.

You think it would be better inline? Ok, I thought that it was better as
a macro, but you have more experience then I. One question though, does
an inline function’s return statement get removed when it is placed
inline since having a return in an inline function would cause the
caller to return?

When the compiler inlines a function, the `execution’ of the function remains identical to as it would be if not
inlined. If the inline function has no return statement, the compiler will give you an error. The only difference in
inlining is that the assembler instructions will be addressed at (and repeatedly if necessary) sections of code when the
function is called rather than separately. For small functions, this can make the register handling much more efficient.

Thanks, that makes it much clearer. You need to edit your post though and disable similes as it messes up the :.

On 2014-07-09, ballsystemlord <ballsystemlord@no-mx.forums.opensuse.org> wrote:
> Thanks, that makes it much clearer. You need to edit your post though
> and disable similes as it messes up the :.

Pleasure. My understanding is that posts cannot be edited, and I know of no way of disabling smilies other declaring a
specified (e.g. code) environment, which I believe cannot be done inline. Moreover, smilies are not respected by the
forum’s NNTP interface and so I have no idea which character conversions are mutated into smilies by the HTML site.

However, I think it’s worth noting that openSUSE’s forum’s provision for programming posts is poor. For example, NNTP
posts of code (inside code tag environment delimiters) are not respected when it comes to space indentation. This makes
Python code posts completely pointless. I’ve already brought this to the attention of forum, but no-one seemed to care
except try to contradict my findings (in vain). So I’ve just accepted that the openSUSE forum is not really geared
towards programmers.

Below the edit window there is a box called (don’t hit quick reply)
Additional Options

it contains a check box labeled

Disable smilies in text

You will need javascript. As for editing your post… umm I don’t see any button.