Does "is_linux" variable have special meaning? - c

I don't understand why the result of the if statement below is always incorrect:
unsigned long is_linux;
printf("plz. enter a digit : ");
gets(str);
sscanf(str,"%d",&is_linux);
printf("the value of is_linux = %d \n",is_linux);
if(is_linux==1)
printf("Here is 1 ! \n");
else
printf("There is 0 ! \n");
I can only get "There is 0 !" statement, even if I entered "1". Furthermore, printf() statement displays the value of is_linux (1) correctly:
plz. enter a digit : 1
the value of is_linux = 1
There is 0 !
It works well if I change the variable to another name, for instance,test. Is there any reason for not using is_linux variable ? I've compiled above source code using gcc at x86_64-redhat-linux.

In your code
sscanf(str,"%d",&is_linux);
causes undefined behavior.
is_linux is of type unsigned long, it demands the conversion specifier to be lu.
Passing wrong (mismatched) type of argument to any conversion specifier causes undefined behavior.

No. You should be able to use the variable name. is_linux is not reserved and it's not a keyword. Worst-case scenario, it could (but shouldn't) be a macro (linux commonly is, unfortunately). Preemptively, or if you get compilation errors because it is a macro on your platform, you could #undef it first.
(Make sure the rest of your code is correct.)

The datatype you are assigning to is_linux is not compatible. You set it as a long, but giving it an int so when you check with your if statement you are checking for a long value, not int.

Thank you so much, there.
All comments were very helpful to me for finding root cause.
Actually, it was very simple reason, data type.
Simply, I changed %d to %lu in both of sscanf and printf and got correct answer.
My machine was 64bit lunux system and it treated unsigned long as 8-byte unit.
And also, I misunderstood %d could cover all the integer data types.
Anyway, I'm very appreciate all you guy's comments. Thank you :)

Related

Why compiler is not issuing error while passing an int (not int *) as the argument of scanf()?

I tried the below c program & I expected to get compile time error, but why compiler isn't giving any error?
#include <stdio.h>
#include <conio.h>
int main()
{
int a,b;
printf("Enter a : ");
scanf("%d",&a);
printf("Enter b : ");
scanf("%d",b);
printf("a is %d and b is %d\n",a,b);
getch();
return 0;
}
I am not writing & in scanf("%d",b). At the compile time , compiler don't give any error but during execution value of b is 2686792(garbage value).
As per C11 standard, Chapter §6.3.2.3
An integer may be converted to any pointer type. Except as previously specified, the
result is implementation-defined, might not be correctly aligned, might not point to an
entity of the referenced type, and might be a trap representation.
So, the compiler will allow this, but the result is implementation-defined.
In this particular case, you're passing b to scanf() as an argument, which is uninitialized, which will cause the program to invoke undefined behaviour, once executed.
Also, printf() / scanf() being variadic functions, no check on paramater type is perforfmed in general, unless asked explicitly through compiler flag [See -Wformat].
It is not a a compile time error but a runtime issue.
The compiler expects that you have given a valid address to scan the value to, during runtime only it will come to know whether the address is valid or not .
If you try to scan the value to invalid address it leads to undefined behavior and might see a crash.
It scans fine because scanf expects a memory location in its argument. That's why we use & to give memory location of the corresponding variable.
In your case scanf just scans the entered value and puts it in the memory location which has the value of b(instead of scanning and putting it in the memory location where b is stored).
The & operator in C returns the address of the operand. If you give just the b without the & operator, it will be passed by value and the scanf won't be able to set the value. This would result in unexpected behaviour as you already noticed. It has no way of verifying the address before the runtime and hence you won't notice the issue until runtime.

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.

Why and how does printf pick out matching arguments?

Someone has asked me, why this code produces a random number:
double a = 75.0;
printf("%d\n", a);
I thought the reason was that 4 bytes of the double are interpreted as an integer, but the printed value was different each time the program was run. So i started to try some more things and found that this:
printf("%d\n", 75.0, 6);
actually prints out number 6. So i thought that the compiler is trying to fix the arguments so that they match the format string, but then i tried this:
const char *formats[] = { "%d %.1f\n", "%.1f %d\n" };
int whichFormat = 0;
scanf("%d", &whichFormat);
printf(formats[whichFormat&1], 2.5, 7, 1.2);
The formatting string now isn't even known at compile time, but it still somehow manages to match the argument types to the formatting string, printing either 7 2.5 or 2.5 7 depending on the input. The last value (1.2) was not printed.
All of this can be reproduced at compileonline.com which claims to be using GNU GCC 4.8.1.
What is going on here?
Undefined behavior is going on.
Such behavior is undefined, so it's very hard to reason about, and also somewhat pointless to do experiments, since there's no guarantee that the behavior stays the same (i.e. well-defined) for the same input. The behavior is, after all, undefined.
The first example, for instance, might read an expected integer argument from one register, while the actual floating-point argument is in another. I'm not saying this is what happens on any known machine, but it could be like that.

C function printf() limited in length?

Upon calling the sprintf function to format a string, something unexpected was printed
printf("%d;%s;%s;%d;%d;\n", ptr->programmaType, ptr->titel, ptr->zender, ptr->start, ptr->einde);
prints "0;Stargate;scifi;0;0;" while
printf("%d;", ptr->einde);
prints "42", which is the value of ptr->einde. I've also tried
printf("%d;%s;%s;%d;%d;", 0, "Stargate", "scifi", 0, 42);
which prints correctly, so I'm guessing the problem is related to the variables. Last thing I tried was
int bug = ptr->einde;
printf("%d;%s;%s;%d;%d;\n", ptr->programmaType, ptr->titel, ptr->zender, ptr->start, bug);
which also failed to print correctly... I have no idea what the hell is happening.
Note: ptr->start and ptr->einde are defined als time_t types, but seeing as printf works with a single argument I doubt that's a problem.
You said that ptr->start and ptr->einde are time_t type. This type is not not fully portable and can be any "integer or real-floating type", so it's possible that they are not being handled correctly on your system when you try to print them as int types.
Try casting it to something known and then printing:
printf("%d;%s;%s;%ld;%ld;\n", ptr->programmaType, ptr->titel,
ptr->zender, (long)ptr->start, (long)ptr->einde);
I guess your definition of ptr->einde is not of type int.
And you are using "%d" in the printf specifier which expects an int value.
Use the correct specifier for the correct type and printf behaves.
No printf is not limited in length, except in embedded implementations where it must be able to print at least 4095 chars.
time_t is probably a 64 bit integer value. The solution is to cast your variable to (uint64_t) and using PRIu64 format specifier.
printf("%d;%s;%s;%"PRIu64";%"PRIu64";\n",
ptr->programmaType,
ptr->titel, ptr->zender,
(uint64_t)ptr->start,
(uint64_t)ptr->einde);

Implicit conversion in C?

What's going on here:
printf("result = %d\n", 1);
printf("result = %f\n", 1);
outputs:
result = 1
result = 0.000000
If I ensure the type of these variables before trying to print them, it works fine of course. Why is the second print statement not getting implicitly converted to 1.00000?
In the second case you have a mismatch between your format string and the argument type - the result is therefore undefined behavio(u)r.
The reason the 1 is not converted to 1.0 is that printf is “just” a C function with a variable number of arguments, and only the first (required) argument has a specified type (const char *). Therefore the compiler “cannot” know that it should be converting the “extra” argument—it gets passed before printf actually reads the format string and determines that it should get a floating point number.
Now, admittedly your format string is a compile-time constant and therefore the compiler could make a special case out of printf and warn you about incorrect arguments (and, as others have mentioned, some compilers do this, at least if you ask them to). But in the general case it cannot know the specific formats used by arbitrary vararg functions, and it's also possible to construct the format string in complex ways (e.g. at runtime).
To conclude, if you wish to pass a specific type as a “variable” argument, you need to cast it.
An undefined behavior. An int is being treated as float
The short answer is that printf isn't really C++. Printf is a C function which takes a variable argument list, and applies the provided arguments to the format string basis the types specified in the format string.
If you want any sort of actual type checking, you should use streams and strings - the actual C++ alternatives to good old C-style printf.
Interesting, presumably it's fine if your put '1.0'
I suppose the printf only gets the address of the variable, it has no way of knowing what it was. But I would have thought the compiler would have the decency to warn you.

Resources