macro syntax induced error - c

I the following code and a small little part of it didn't make sense because it was beyond the knowledge I have currently and I was wondering if someone could clear this little problem out for me
stack.h
#ifndef _STACK_H
#define _STACK_H
#include "lis1.h"
typedef List Stack ;
#define stack_init list_init
#define stack_destroy list_destroy
#define stack_size(stack) (stack)->size
#define stack_is_empty(stack) ((stack)->size==0)?1:0
int stack_push(Stack*stack,void*data);
int stack_pop(Stack*stack,void**data);
#endif
please note the #define stack_is_empty(stack) ((stack)->size==0)?1:0 carefully
and on compilation of the following program ,
#include<stdio.h>
#include"stack.h"
static char ams[5] = { 'h', 'e', 'l', 'l', 'o' };
void* data;
Stack stack;
char*ss;
void debug(int a)
{
printf(" debug %d \n", a);
}
int main()
{
stack_init(&stack, NULL);
debug(1);
int i;
for (i = 0; i < 5; i++)
{
stack_push(&stack, (void*) (&ams[i]));
};
debug(2);
while (printf("checker\n") && stack_is_empty(&stack) != 1)
{
printf("->");
printf("[%d ", stack_size(&stack));
stack_pop(&stack, &data);
printf("%c]", *((char*) data));
printf("--\n");
};
return 0;
}
I get this
debug 1 debug 2 checker
->[5 o]-- checker
->[4 l]-- checker
->[3 l]-- checker
->[2 e]-- checker
->[1 h]-- checker
segmentation fault
but if I change #define stack_is_empty(stack) ((stack)->size==0)?1:0
to #define stack_is_empty(stack) (((stack)->size==0)?1:0), there is no seg fault
My Query
My question why did the program work perfectly fine in the former case until the conditional spews a '1'..I seem to understand why the latter works.

In C, a macro is just substituted textually, with no regard to whether it produced the expression that you might expect.
Without the parentheses, your while loop condition expands to:
printf("checker\n")&&((&stack)->size==0)?1:0!=1
Which is interpreted as:
(printf("checker\n") && ((&stack)->size==0)) ? 1 : (0 != 1)
The printf thus becomes part of the condition for this ternary expression, but that's doesn't cause a problem, it returns the number of bytes printed which will be interpreted as true as long as it's non-zero. Then you perform an and with your actual condition, the part that checks the stack size. If the stack size is equal to zero, this returns 1, or true. If the stack size is not equal to zero, this returns the result of (0 != 1), which is always true. So this condition always returns a true value, and the while loop keeps going, even after it's run out of items on the stack.
When you add the parentheses, it's interpreted as you expected:
printf("checker\n") && ((((&stack)->size==0)) ? 1 : 0) != 1)
When writing macros that expand to an expression, you should always have a pair of parentheses around the result, to ensure that it is interpreted as a single expression, rather than operator precedence rules possibly causing the expression to be interpreted differently than you intended.
I should note that there is a lot of redundancy in this statement. You are checking the value of a boolean expression, (&stack)->size==0 to see if it is true, returning 1 if it is and 0 if not. But the == already returned a 1 if it was true and a 0 if not; there's no need for the ternary operator. Then you use != 1 to see if it's false. But how do you get false from a boolean expression? Simply use the not operator, !. You can skip the ternary operator and != 1 comparisons entirely:
#define stack_is_empty(stack) ((stack)->size==0)
while (!stack_is_empty(&stack)) {
// ...
}

Remember that C macros are just text replacement, NOT expression evaluations.
Using your umbra keyed stack_is_empty, your if condition becomes :
While (printf("checker\n") && ((&stack)->size)==0)?1:0!=1) {
Trouble is, the != operator has high precedence, so it effectively becomes :
While (printf("checker\n") && ((&stack)->size)==0)?1: (0!=1) ) {
Since 0 != 1, that while loop is going to keep going beyond the size of your stack.

After the macro substitution
printf("checker\n")&&stack_is_empty(&stack)!=1
becomes
printf("checker\n")&&((&stack)->size==0)?1:0!=1
because the ternary operator ?: has a fairly low precedence, this is equivalent to:
(printf("checker\n") && ((&stack)->size==0)) ? 1: (0 != 1)
Note that printf("checker\n") always returns a true value(because it returns how many characters it prints), so the check (&stack)->size==0) is never evaluated due to shortcut circuit.
Advice: always use enough parenthesis in macro definition.

Related

Ambiguity about Boolean functions in C

Part of my C code 1:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
[snip!!]
#define FALSE 0
#define TRUE 1
[snip!!]
typedef int Boolean;
[snip!!]
typedef struct {
int identification ;
char name[NAMESIZE] ;
char subject[SUBJECTSIZE] ;
int grade ;
} RECORD ;
typedef struct {
char type ;
RECORD student ;
} TRANSACTION ;
typedef struct {
char occupied ;
RECORD student ;
} MASTER ;
char *prog ;
Boolean get_transaction_record(FILE *fp, TRANSACTION *transaction);
[snip!!]
void main(int argc, char *argv[])
{
FILE *fpmas,*fptrans ;
int current_key ,
relative_record_number ;
Boolean allocated;
TRANSACTION transaction;
MASTER master ;
clrscr();
prog = argv[0];
[snip!!]
else
{
get_transaction_record(fptrans, &transaction) ;
current_key = choose_next_key(transaction.student.identification);
while(current_key != TRAILER)
{
relative_record_number = do_initial_status(
current_key,&allocated, fpmas,&master);
while(current_key == transaction.student.identification)
{
apply_transaction (&allocated, &transaction,&master) ;
get_transaction_record(fptrans, &transaction);
}
do_final_status (fpmas, relative_record_number, allocated, &master);
current_key = choose_next_key(transaction.student.identification);
} //end of while
fcloseall();
} //end of else
}
Part of code 2:
Boolean get_transaction_record(FILE *fp, TRANSACTION *transaction)
{
if (fscanf (fp, "%4d%c%20s%10s%2d",
&transaction -> student. Identification,
&transaction -> type,
transaction -> student.name,
transaction -> student. Subject,
&transaction -> student. Grade) == 5)
return(TRUE);
return(FALSE);
}
How these return(); work (in the screenshot I attached) ?! I see before Boolean application like this typedef int Boolean; before. But that usage was in accompany with if() . But I do not see any if() in this code!
My main question is, how it works when the return value (TRUE or FALSE), get back to main() function'?! In main(), there is no condition evaluation to take decision about that (TRUE or FALSE) returned value. So what?
Boolean - return
First, your C learning book is largely outdated. C99 (out in 1999) allows #include <stdbool.h> that contain a bool type and true/false defines, use these instead of making your own boolean.
C and many other languages are a bit weird with boolean, if and what is true of false. In C what is 0 is false, everything else is true, hence why TRUE is defined as 1 and FALSE defined as 0 in your book. Note that comparison operators such as ==, &&, ||, ! (not to be confused with binary operators &, |, ~) returns either 1 or 0 depending of the condition.
See this example:
#include <stdio.h>
#include <stdbool.h>
bool return_the_truth(void)
{
return true; // A trivial function that returns true.
}
int main(void) {
if (2)
printf("As you see just \"2\" is true since it's different of zero\n");
if (0)
printf("That line won't be printed\n");
if (4 - 4)
printf("Neither this one since 4-4 is zero\n");
if (true == 1)
printf("true is in fact a one.\n");
if (true == 2)
printf("But merely a integer with value 1 so this line won't print.\n");
// You can invoke a function that returns a boolean and ignore it's return value.
return_the_truth();
// It is never mandatory to use the returned value. This example is absurd but perfectly valid
fopen("delete_me.txt","a"); // <- Don't forget to delete this file afterward.
if (printf("printf() return an int that is the numbers of characters printed.\n"))
printf("Hence again, this line is printed because what in the if() is not zero.");
int boolean_check_result = 42 == 40+2;
if (boolean_check_result)
printf("You can write expressions like this, there boolean_check_result is %d.\n",boolean_check_result);
printf("You can performs math with boolean, there is %d true expressions there, it works because a comparison returns 1 if true, 0 if false and we doing a sum of 1 and zeros (it's brainfuck to understand don't do that or people reviewing your code will hate you).\n",
(4 == 5) + (4 < 5) + (4 != 5) + (4 > 5) + (4 >= 5) // <- The expressions.
);
// These examples below are valid C.
5 + 6; // This sum goes to... nothing
7 == 7; // Same for this boolean, nothing will happen
printf; // Functions are kind of constants variables so that works.
// It's a non-sense, a compiler will output warnings because making computations without using the results is likely a programming error.
printf("But remind you that in the case of a function (returning a boolean or not), there might be side-effects you want and don't care about the returned value such as with this printf().\n");
}
// Did you know that you can use a `void` value ?
// The code below is perfectly valid.
// It's useful for C++ wrappers when you want to exactly mimic the behavior a library in order to catch errors.
void a_function_that_does_nothing(void)
{
}
void you_can_return_a_void(void)
{
return a_function_that_does_nothing(); // Allowed because the function return a void
}
There is tons of valid case where a returned boolean are not used inside a if().
So to answer your original question (that I might forgot while writing this answer hehe...):
how it works when the return value (TRUE or FALSE), get back to main()
function'?!
And ! ๐Ÿฅ ๐Ÿฅ ๐Ÿฅ Nothing happens. The value is just lost, just like with printf() and any other functions. In the book the boolean value was an error indicator since scanf() return the number of inputs read, not 5 mean that the input was incorrect.
Not checking it is fine for learning purposes. In real-world input parsing, first don't use scanf(), then it could introduce a security vulnerability since some variables would not be written and in incorrect state and trigger unwanted behavior later that can be exploited by a malicious hacker to leak sensitive data of thousands of customers and costs millions of USD to a company (I'm barely exaggerating).
So don't be outraged when a boolean or other returned value is not used, memcpy() is a function where it's commonly sane to ignore it's return value. What is important is to understand what you are doing.
If you're still extremely angry about the fact that this boolean wasn't used and could avoid a potential security vulnerability... (I'm joking there, yet) as an exercise you can add error checking and do something useful such as printing an expressive error message telling the user that the input is incorrect and remind they what you are expecting and quit.

Why am I getting the answer "odd" instead of "even"

Why am I getting the answer "odd" instead of "even"?
#include<stdio.h>
#define ODD(x) x%2?0:1
int main()
{
int a=5;
if(ODD(a+1))
printf("even");
else
printf("odd");
return 0;
}
ODD(a+1) expands to a+1%2?0:1. With a as 5, that is same as (5+(1%2))?0:1 or 0.
% beats + which beats ?:
if(0)
printf("even");
else
printf("odd"); // print `odd`
Perhaps you wanted some () to insure evaluation order.
// #define ODD(x) x%2?0:1
#define ODD(x) ((x)%2?0:1)
Yet that seems backwards. How about
#define ISODD(x) ((x)%2 != 0)
See How do I check if an integer is even or odd?
1 is treated as true and 0 as false.
if (1) is executed always, and when you get 0 as result, the branch shifts to else
so code should be :
if ODD is true (returning 1 from terneray expression), print "odd"
#define ODD(x) x % 2 ? 0 : 1
Given an even number x, x % 2 will give you zero, which is false.
Hence the result of the entire ternary expression will be the second option 1, which is true.
You would be better off with something like:
#define ODD(x) (((x) % 2) != 0)
It's both more readable in intent, and less prone to errors such as getting the true/false values mixed up, or being burnt by simple text substitution having unexpected effects.
I do not like this kind if macros for many reasons (one of it that they can be a source of silly errors - like in your case). It should be domain of functions.
int ODD(int x)
{
return x & 1;
}
if you are worried about function call overhead just make it inline (but on any level op optimisation the compiler will inline it anyway as the call is probably longer than the function itself.

Pre-Processor C Macro Syntax

I am trying to understand the Pre-Processor syntax. Its really simple line of code that either returns "ON" or "OFF". However I am utterly confused as to what exactly the condition is?
I understand C's conditional statement as follows:
? x : y
If Condition ? return - replace? x : or y either way this line of code is as follows:
#define ONOFF(a) ((a) ? "ON" : "OFF")
I don't understand what condition must be met here? Is the condition that a has to be something other than null?
True and Flase can be more perfectly presented as 1 or 0 . As I can see you have declared
#define ONOFF(a) ((a) ? "ON" : "OFF")
Your condition here is (a), which istrueif the value ofa is non zero and false if ais 0
Which means in your program, if you write
int a=1;
char *str;
str=ONOFF(a);
The substitution which takes place is
int a=1;
char *str;
str=((a) ? "ON" : "OFF")// here a=1
Since here a is 1 and
1 is true and str gets the value ON. If a were 0, then str would get the value OFF
The condition is that a has to evaluate to true. In c, that means that a must be an expression that is non-zero.
If a is a pointer type, NULL is false and any other value is true.
If a is an integer type, 0 is false and any other value is true.
If a is a floating point type, 0 is false and any other value is true.
If a is a struct or a void type you will get a compile error.
To add a bit of context here, the first operand of the conditional operato has to be of scalar type. Now, from chapter ยง6.2.5, of C11,
Arithmetic types and pointer types are collectively called scalar types.
So, for the conditional expression,
any non-zero value gets evaluated as TRUE and zero (0) is evaluated as FALSE.
(In case of pointers) a NULL is FALSE, any non-NULL is TRUE.
Preprocessor macros do textual substitution, so a is not a variable -- it's just a placeholder for whatever text is in the parentheses when the macro is used.
You could use it for checking pointers are not null like this:
printf("%s\n", ONOFF(ptr));
printf("%s\n", ONOFF(ptr != null)); // This is the same
Or any other type of condition you like:
printf("%s\n", ONOFF(a > b));
printf("%s\n", ONOFF(a && b));
printf("%s\n", ONOFF(a == 1 || c == 4));
printf("%s\n", ONOFF(somefunction() != 0));
printf("%s\n", ONOFF((a == b && c == d) || (a == c && b == d));
printf("%s\n", ONOFF(my_bool_value));

Passing an array through "isalpha" through a loop

I've been at this for quite some time now and the existing answers offer little to no help. I am new to programming and am trying to write a sub-part of my program which tries to check whether any given input is constituted solely of alphabets.
For this, the idea I have in mind is to pass an entire array through the isalpha function by using a loop which passes each character at a time. The idea makes logical sense but I am having syntactic trouble implementing it. I will greatly appreciate any help!
Below is my code-
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(**<what I'm putting here is creating the problem, I think>**) = true)
{
printf("%c", p[i]);
}
}
You should modify your code as this (assuming you have the string type defined yourself):
printf("Please type the message which needs to be encrypted: ");
string p = GetString();
for (int i = 0, n = strlen(p); i < n; i++)
{
if(isalpha(p[i]) == true) // HERE IS THE ERROR, YOU HAD =, NOT ==
{
printf("%c", p[i]);
}
}
Operator = is for assignment and operator == is for comparison!
So what was happening? The assignment resulted in true, no matter what p[i] was.
As Quentin mentioned:
if(isalpha(p[i]) == true)
could be more elegant and error prune if written like this:
if(isalpha(p[i]))
Here is an example in C:
/* isalpha example */
#include <stdio.h>
#include <ctype.h>
int main(void)
{
int i = 0;
char str[] = "C++";
while (str[i]) // strings in C are ended with a null terminator. When we meet
// the null terminator, while's condition will get false.
{
if (isalpha(str[i])) // check every character of str
printf ("character %c is alphabetic\n",str[i]);
else
printf ("character %c is not alphabetic\n",str[i]);
i++;
}
return 0;
}
Source
Ref of isalpha().
C does not have a string type.
Tip: Next time post your code as it is!
Aslo, as Alter noticed, it would be nice to use:
isalpha((unsigned char)str[i])
and in your code
isalpha((unsigned char)p[i])
for safety reasons.
Your example is here.
I.e. parameter of isalpha() is i-th character of string p. The only question is how to access to i-th character. Usually you can use []. I.e. just use following code: isalpha(p[i]) (I see that you already use [] in call of printf).
Also isalpha(p[i]) = true is wrong condition. It looks like you planned to check isalpha(p[i]) == true (you can skip == true).
Late but:
both other answers say omitting == true is desirable, but don't say it is necessary for portability.
The C core-language operators == != < <= > >= && || which return a 'logical' value use an int value of 1 for true and 0 for false. In C99 and up with stdbool.h and by common convention before that true is 1 and false is 0, so e.g. if( (a < b) == true ) will work correctly, although it is redundant and many (including me) consider it poor style. Language elements that test a logical value, namely if(c) while(c) for(;c;) and the operands to && || and the left operand to ?: consider any value that compares equal to 0 to be false, and any other value to be true.
The character-classification routines in ctype.h as well as some other standard-library routines like feof(f) and ferror(f) are specified to return some nonzero int for true and 0 (an int) for false, and on many implementations the nonzero value used for true is not (always) 1. In those cases isalpha(whatever) == true might result in testing say 4 == 1 and fail even when whatever is an alphabetic character. OTOH isalpha(...) != false or isalpha(...) != 0 does work correctly if you really want to write something explicit.

assignment works as a condition

Consider the following Code,
int i;
while(i=0)
printf("Hello");
Now Generally speaking i=0 is an assignment and not a condition for while to check.
But the GCC compiler lets it go with a warning and even evaluates it correctly (does not execute the print statement).
Why? I usually would do with parenthesis for the truth value but my juniors feel that I am wrong and there is no real reason for the parenthesis in this!
EDIT: Zeroing down on the 'actual' doubt, Please consider the following test case
int callme(){
return 0;
}
int main(int argc,char*argv[]){
int c;
while(c = callme()){
printf("Calling...\n");
}
return 0;
}
The expression i = 0 does 2 things:
Has the side effect of storing o in i
Yields the value 0
I usually would do with parenthesis for the truth value but my juniors
feel that i am wrong and there is no real reason for the parenthesis
in this
It's usually a hint to the compiler meaning "I actually want this, I didn't forget a =, shut up".
For your specific case there's no reason to write if (i = 0): you already know what if (0) does. But it's pretty useful when used as:
if ((i = some_function()))
...
i=0 is always an assignment (unless you have it as part of int i = 0; where it is an initialization). But any non-void expression may appear inside the condition of a while loop and if it evaluates to non-zero, the body of the loop will be executed, and if it is zero, the body of the loop will not be executed.
The notation:
while (i = 0)
printf("Hello\n");
is always equivalent to:
i = 0;
There is very little justification for writing the loop at all.
People do write other expressions:
while (c = getchar())
...process EOF or a non-null character...
But that's usually a bug. It is more likely that you should be writing:
while ((c = getchar()) != EOF)
...process a character - possibly null...
or even:
while ((c = getchar()) != EOF && c != '\0')
...process a non-null character...
The first getchar() loop gets a warning from GCC; the latter two do not because of the the explicit test of the value from the assignment.
The people who write a condition like this:
while ((c = getchar()))
really annoy me. It avoids the warning from GCC, but it is not (IMNSHO) a good way of coding.
When you use an assignment operator such as
a=0;
You assign the value to 'a', and still return the number 0.
To test your question, I tried these lines of codes:
int a;
printf("%d", a=0);
and these lines displayed 0.
Then, I tested another set of codes:
int b;
printf("%d", b=15);
Here, the lines displayed 15.
So, if you do:
while(a=0)
{
printf("zero");
}
The (a=0) statement would return false, thus not displaying anything.
But if you do:
while(a=15)
{
printf("fifteen");
}
The "fifteen" will be displayed endlessly, because the statement (a=15) will return a non zero value, or 15, which is not false, not zero, thus it is true. :)
As cnicutar has told above the assignment also yields the value zero.
Some additional info:
It is a common coding mistake for people to omit an extra '=' whereby the comparison becomes an assignment.
An easy way to avoid this is to write the comparison as below, in which case even if a '=' is missed compiler will give an error
while(0 == i)
{
prinf("Hello");
}

Resources