MinGW with GCC on Windows misreporting numeric values - c

For some reason, whenever I use a numeric value in my compiler set-up (MinGW on Windows, using a CMD prompt to compile and run), it completely misreports numbers in the program.
Code example:
//C hello world example
#include <stdio.h>
int main()
{
int value;
value = 10;
printf("The number is %d \n"), value;
int value2;
value2 = -100;
printf("The number is %d \n"), value2;
return 0;
}
Cf. screenshot of output.

value and value2 have to be passed as arguments, i.e. within the parantheses. Change it to the following:
printf("The number is %d \n", value);
And do similarly with value2.
Once again, this shows that compiling with -Wall and -pedantic switches on is useful. GCC most likely would have issued a warning message.

By saying
printf("The number is %d \n"), value;
you're somehow making (mis)use of the "comma operator" , so no syntax error is produced. Your print statement is considered as
printf("The number is %d \n");
and value si executed as a void expression.
Now, printf() being a variadic function, it does not check for the required number of arguments for supplied format specifiers (by default), but, point to note, as per the required format for printf(), you're essentially missing out the operand to the %d format specifier. This in turn invokes undefined behaviour.
As the standard mandates
If there are insufficient arguments for the format, the behavior is
undefined.
The correct syntax will be
printf("The number is %d \n", value);
where the value will be the argument to %d format specifier.
Moral of the story: Enable compiler warning and pay heed to them.
Note: Some suggestions,
The recommended signature of main() is int main(int argc, char**argv), or, atleast int main(void).
Try to get into a habit of defining and initialize any variable at the same time. Will save you from the danger of ending up using uninitialized value (local variables) at later part.

Related

Printing with format specifiers in C

In a class quiz, I was asked to write the output of the below code snippet.
x = 1.234;
printf("x=%2d");
The variable x contains point values so I assumed it to be a float/double type.
In the paper I answered that this code would just simply print the statement within quotes (as x=%2d), as in print function it prints whatever within the " " as it is.
But later I ran the code in my compiler to find the output as x=4199232 (The number varied in different compilers though)
(Edit- I added the compiled code here)
#include <stdio.h>
int main() {
float x = 1.234;
printf("x=%2d");
return 0;
}
Can anybody kindly explain me what is really happening here.
The code has undefined behavior (which explains why the number varied in different compilers) because you do not provide an argument of type int for the conversion %2d.
If you had written this:
x = 1.234;
printf("x=%2d", x);
The output would depend on the type of x which does not appear in the code fragment. If x is defined with type int or a smaller integer type, including _Bool, the output should be x= 1, but if x has any other arithmetic type, including float and double, the behavior is again undefined because the argument does not have the expected type for %d.
Note also that there is no trailing \n in the format string, so the output might be delayed until the end of the program and might not appear at all on some non conformant systems.
In your sample code, the behavior is undefined because of the missing argument to printf, but you do define x as a float, which would be implicitly converted as a double when passed to printf, invalid for %d.
Here is a modified version:
#include <stdio.h>
int main() {
double x = 1.234; // only use `float` when necessary
printf("x=%2d\n", (int)x); // outputs `x= 1`
printf("x=%2f\n", x); // outputs `x=1.234000`
printf("x=%2g\n", x); // outputs `x=1.234`
printf("x=%.2f\n", x); // outputs `x=1.23`
return 0;
}
In this statement
printf("x=%2d");
you forgot to specify an argument for the conversion specifier d. So the program will try to output whatever is stored in the memory where the second argument should be.
So the program has undefined behavior.
It will also have undefined behavior if you will specify the second argument like
printf("x=%2d", x );
because there is used an invalid conversion specifier with an object of the type float.
To output just the format string you should write
printf("x=%%2d");

Macro variable substitution in printf

I wrote a simple program with a single printf statement,like hello world.
#include <stdio.h>
#define MAX 100
int main()
{
printf("Max is %d\n",MAX);
}
I studied that macros are just substituted in place of occurrence ,by preprocessor. Generally printf need a variable name with corresponding format specifier to print the value of variable.
Here ,with my understanding, 100 should be replaced in printf call and should raise an error.
But the output is :
Max is 100
How and why?
"Generally printf() need a variable name with corresponding format specifier to print the value of variable."
There you went wrong. All the format specifiers supplied with printf() expects an argument of the particular type, not a variable of that type. 100, an integer literal, is a valid argument for %d, in this case.
So, printf("Max is %d\n",100); is both a valid and legal statement in C. The output you got is expected output, there should be no error or warning with this.
Just to add a reference to the actual words, quoting C11, chapter §7.21.6.1, fprintf() (emphasis mine)
d,i
The int argument is converted to [...]
The printf format "%d" tells printf to extract an int argument from the argument list. If that int comes from a variable or a literal doesn't matter.

Functions and arguments giving error

The result of this code down below should be 30, however when compiled and run this is giving me the following result
the result of 2358968 and 0 is 4200271, a , b , result
I
don't understand when I have no variables of that value how could the result be like that?
#include<stdio.h>
#include<conio.h>
void add( int , int );
int main(){
add(10,20);
getch();
return 0 ;
}
void add(int a, int b){
int result = a + b;
printf("the result of the %d and %d is %d, a, b, result");
}
In your code,
printf("the result of the %d and %d is %d, a, b, result");
should be
printf("the result of the %d and %d is %d\n", a, b, result);
^
|
//format string ends here
// arguments for format specifiers are meant to be
// supplied as different arguments to `printf()`, not as a part of <format> string itself
From the man page of printf()
int printf(const char *format, ...);
and
The functions in the printf() family produce output according to a format ....
So basically your code should be
printf("<format>", var1, var2,....);
The supplied variables are not part of the format.
The problem in your code were missing variables (arguments) for supplied format specifiers. As per the C11 standard , chapter 7.21.6.1, paragraph 2
[...] If there are insufficient arguments for the format, the behavior is
undefined. [...]
So, your code produces undefined behaviour printning out some junk value.
Moral of the Story : If you had enabled compiler warnings, you compiler should warn you about missing (mismatch) agruments in printf(). So, always enable warnings.
You have closed the " at the end of the line. and in the printf function you have specified the %d So the %d will not have the variable to point and fetch the value.
You will get the warning message that %d expects a matching int
It will have the garbage value in that position, So it is printing some value.
Sourav Ghosh answered to most of your questions; he rightly suggested to enable all warnings when compiling. If your compiler is (notably on Linux) some recent GCC or Clang/LLVM pass -Wall -Wextra -g to the gcc or clang command (to get nearly all warnings, some extra ones, and debug information). Others compiler options (-fsanitize=address etc etc...) and other tools (the gdb debugger, the valgrind tool, strace, ...) might be useful too!
I dont understand when I have no variables of that value how could the
result be like that?
Because you have encountered undefined behavior. Read much more about it (in particular Lattner's blog on What Every C Programmer should know about Undefined Behavior), and work hard to always avoid it in all cases. Be aware that with UB, your (or any other) program might seems to work while in fact it has some undefined behavior.
The particular garbage (or apparently random) values that are printed : might not be reproducible, and can be explained only by diving into every implementation details, including looking into the machine code generated by your particular compiler and inspecting some machine state (register values); concretely the printf implementation on your system is probably using some stdarg(3) things and fetching some values from uninitialized memory or register which happens to have some previous "garbage" value (at the machine level).
See also this answer (and many others) about undefined behavior. Work hard to always avoid it.
Remember that when coding (even in C) you are ultimately coding for some virtual or abstract machine which is not the real computer. Even if writing all the software levels from the operating system kernel included - that would take you many dozens of years at least -, you are coding for some specified abstraction and you have to ignore some misbehavior of your computer (e.g. if it breaks, get some cosmic rays, etc etc...) outside of these abstractions. The C99 or C11 programming language standard specification (a technical document of several hundred pages in English), with the POSIX 2008 operating system specification, are useful abstractions to code software for.
printf statement is the reason for undesired output,
printf("the result of the %d and %d is %d, a, b, result");
There is no arguments specified for format specifier, the position of " has to be changed.
the statement should be like this
printf("the result of the %d and %d is %d", a, b, result);
In your printf statement it was taking garbage value since no arguments were specified there for %d.
printf("the result of the %d and %d is %d, a, b, result");
it has to be
printf("the result of the %d and %d is %d", a, b, result);
it will read and assign the %d value from left to write.
printf returns number of characters

strtof() producing weird results in C

first of all, compiling with flags -Wall, -ansi, -pedantic. no warnings or errors. and no debugging is helping.
basically my code is working fine however returning very weird and unexpected results when I turn a token from a string to a float using strtof()
the section of code below is:
printf("token is %s\n", token);
newstockdata->unitPrice = strtof(token, NULL);
printf("price is %d\n", newstockdata->unitPrice);
newstockdata is allocated to the correct size: unitPrice is a float variable: the first printf statement prints "150.00": the second printf statement prints "0" but after a few iterations it returns a really long consistent number. any help please?
The problem is here, assuming that unitPrice is a float:
printf("price is %d\n", newstockdata->unitPrice);
To print a float you must use the %f specifier. Otherwise, it is undefined behaviour and anything could happen.
A possible explanation of the changing values you see might be that your system passes floats in a different register to ints. The printf receiving %d is looking in a register that is never set, so you are seeing whatever value was left over from some previous operation.
This is actually pretty common, here is an example - %esi is used for the int, and %xmm0 is used for the floating-point value.
You have to handle overflow cases. After calling strtof() check errno for overflow. If you think the values could be very long, you can use double or long double.

C variable assignment issue

I think the title does not suit well for my question. (I appreciate it, if someone suggests an Edit)
I am learning C with "Learn C The Hard Way.". I am using printf to output values using format specifiers. This is my code snippet:
#include <stdio.h>
int main()
{
int x = 10;
float y = 4.5;
char c = 'c';
printf("x=%d\n", x);
printf("y=%f\n", y);
printf("c=%c\n", c);
return 0;
}
This works as I expect it to. I wanted to test it's behavior when it comes to conversion. So everything was ok unless I made it to break by converting char to float by this line:
printf("c=%f\n", c);
Ok, I'm compiling it and this is the output:
~$ cc ex2.c -o ex2
ex2.c: In function ‘main’:
ex2.c:13:3: warning: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘int’ [-Wformat=]
printf("c=%f\n", c);
^
The error clearly tells me that It cannot convert from int to float, But this does not prevent the compiler from making an object file, and the confusing part is here, where I run the object file:
~$ ./ex2
x=10
y=4.500000
c=c
c=4.500000
As you can see printf prints the last float value it printed before. I tested it with other values for y and in each case it prints the value of y for c. Why this happen?
Your compiler is warning you about the undefined behaviour you have. Anything can happen. Anything from seeming to work to nasal demons. A good reference on the subject is What Every C Programmer Should Know About Undefined Behavior.
Normally, int can convert to double just fine:
int i = 10;
double d = i; //works fine
printf is a special kind of function. Since it can take any number of arguments, the types have to match exactly. When given a char, it is promoted to int when passed in. printf, however, uses the %f you gave it to get a double. That's not going to work.
Here is how one would implement their own variadic function, taken from here:
int add_nums(int count, ...)
{
int result = 0;
va_list args;
va_start(args, count);
for (int i = 0; i < count; ++i) {
result += va_arg(args, int);
}
va_end(args);
return result;
}
count is the number of arguments that follow. There is no way for the function to know this without being told. printf can deduce it from the format specifiers in the string.
The other relevant part is the loop. It will execute count times. Each time, it uses va_arg to get the next argument. Notice how it gives va_arg the type. This type is assumed. The function needs to rely on the caller to pass in something that gets promoted to int in order for the va_arg call to work properly.
In the case of printf, it has a defined list of format specifiers that each tell it which type to use. %d is int. %f is double. %c is also int because char is promoted to int, but printf then needs to represent that integer as a character when forming output.
Thus, any function that takes variadic arguments needs some caller cooperation. Another thing that could go wrong is giving printf too many format specifiers. It will blindly go and get the next argument, but there are no more arguments. Uh-oh.
If all of this isn't enough, the standard explicitly says for fprintf (which it defines printf in terms of) in C11 (N1570) §7.21.6.1/9:
If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.
All in all, thank your compiler for warning you when you are not cooperating with printf. It can save you from some pretty bad results.
Since printf is a varargs function, parameters cannot be converted automatically to the type expected by the function. When varargs functions are called, parameters undergo certain standard conversions, but these will not convert between different fundamental types, such as between integer and float. It's the programmer's responsibility to ensure that the type of each argument to printf is appropriate for the corresponding format specifier. Some compilers will warn about mismatches because they do extra checking for printf, but the language doesn't allow them to convert the type -- printf is just a library function, calls to it must follow the same rules as any other function.
Here is a very general description, which may be slightly different depending on the compiler in use...
When printf("...",a,b,c) is invoked:
The address of the string "..." is pushed into the stack.
The values of each of the variables a, b, c are pushed into the stack:
Integer values shorter than 4 bytes are expanded to 4 bytes when pushed into the stack.
Floating-point values shorter than 8 bytes are expanded to 8 bytes when pushed into the stack.
The Program Counter (or as some call it - Instruction Pointer) jumps to the address of function printf in memory, and execution continues from there.
For every % character in the string pointed by the first argument passed to function printf, the function loads the corresponding argument from the stack, and then - based on the type specified after the % character - computes the data to be printed.
When printf("%f",c) is invoked:
The address of the string "%f" is pushed into the stack.
The value of the variable c is expanded to 4 bytes and pushed into the stack.
The Program Counter (or as some call it - Instruction Pointer) jumps to the address of function printf in memory, and execution continues from there.
Function printf sees %f in the string pointed by the first argument, and loads 8 bytes of data from the stack. As you can probably understand, this yields "junk data" in the good scenario and a memory access violation in the bad scenario.

Resources