Is the %zu specifier required for printf? - c

We are using C89 on an embedded platform. I attempted to print out a size_t, but it did not work:
#include <stdio.h>
int main(void) {
size_t n = 123;
printf("%zu\n",n);
return 0;
}
Instead of 123, I got zu.
Other specifiers work correctly.
If size_t exists shouldn't zu also be available in printf?
Is this something I should contact my library vendor about, or is a library implementation allowed to exclude it?

If size_t exists shouldn't zu also be available in printf?
size_t existed at least since C89 but the respective format specifier %zu (specifically the length modifier z) was added to the standard only since C99.
So, if you can't use C99 (or C11) and had to print size_t in C89, you just have to fallback to other existing types, such as:
printf("%lu\n", (unsigned long)n);

size_t is returned by sizeof(). %zu specifier prints the length.So to return the size of n,the code should read: #include <stdio.h>
int main(void) { size_t n=123; printf("%zu\n",sizeof (n)); return 0;` }

This is working fine. In my system, it's printing the expected value.
You may be getting the error due to the compiler. I am using the GCC compiler. If you have this only and trying to get the output the first update the GCC and then try. It will work.

Related

Memory allocation after declaration of extern class variable

I have read in multiple places that when declaring an extern variable, the memory is not designated until the definition is made. I was trying this code which is giving contradictory output in gcc.
#include <stdio.h>
int main() {
extern int a;
printf("%lu", sizeof(a));
return 0;
}
it should have shown error or zero size. but the output was following. please justify the output. Is it example of another undefined behavior?
aditya#theMonster:~$ ./a
4
You're able to get away with it here because a is never actually used. The expression sizeof(a) is evaluated at compile time. So because a is never referenced, the linker doesn't bother looking for it.
Had you done this instead:
printf("%d\n", a);
Then the program would have failed to link, printing "undefined reference to `a'"
The size of a variable is the size of its data type, whether it is presently only an extern or not. Since sizeof is evaluated at compile time, whereas symbol resolution is done at link time, this is acceptable.
Even with -O0, gcc doesn't care that it's extern; it puts 4 in esi for the argument to printf: https://godbolt.org/z/Zv2VYd
Without declaring a, however, any of the following will fail:
a = 3;
printf("%d\n", a);
int *p = &a;
The a is an integer, so its size is 4.
Its location(address) and value are not currently known.(it is extern somewhere at some other location)
But the size is well defined.
size_t sizeof(expr/var_name/data_type) 1 is a unary operator which when not provided with a variable length array, do not evaluate the expression. It just check the data type of expression.
Similarly, here, in sizeof(a), the complier only checks the data type of a which is int and hence returns the size of int.
Another example to clear your confusion is in sizeof(i++), i do not get incremented. Its data type is checked and returned.
One more example:
void main(){
int p=0;
printf("%zu",sizeof(p=2+3.0));
printf("%d",p);
}
will give u output on gcc as:
4
0
There is indeed a problem in your code, but not where you expect it:
passing a value of type size_t for printf conversion specification %ld has undefined behavior if size_t and unsigned long have different sizes or representations, as is the case on many systems (16-bit systems, Windows 64-bit...).
Here is a corrected version, portable to non C99-conforming systems, whose C library printf might not support %zu:
#include <stdio.h>
int main(void) {
extern int a;
printf("%lu\n", (unsigned long)sizeof(a));
return 0;
}
Regarding why the program compiles and executes without an error:
Variable a is declared inside the body of main with extern linkage: no space is allocated for it and a would be undefined outside the body of main.
sizeof(a) is evaluated at compile time as the constant value sizeof(int), which happens to be 4 on your platform.
No further reference to a is generated by the compiler, so the linker does not complain about a not being defined anywhere.

Why does strtof not print proper float?

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(){
char aaa[35] = "1.25";
char* bbb = &(aaa[0]);
char** ccc = &(bbb);
float a = strtof(*ccc, ccc);
printf("%f\n", a);
return 0;
}
The code I wrote above should print 1.25, but according to codepad (online C compiler), it does not print 1.25. On codepad, it prints 2097152.000000 . Here's the codepad link
What have I done wrong here?
codepad has an old version of gcc, and presumably of the standard C library. Apparently, strtof is not being declared by the header files you include. (strtof was added in C99.)
Try using an online service with a postdiluvian version of gcc. Or explicitly add the correct declaration:
float strtof(const char* ptr, char** end_ptr);
What's happening is that without the declaration, the compiler defaults the return type of the function to int. Since the function actually returns a float, the float is being interpreted as (not converted to) an integer, and then that integer is converted to a float.
No warning is produced, presumably because -Wall is not in the compiler options, and/or the C standard being used allows the use of non-declared functions.

c sscanf and SCNu64 compile error

I don't understand the below error message when I compile this code. I couldn't find out what wrong with it.
Description Resource Path Location
Type expected ‘)’ before ‘SCNu64’.
#include <inttypes.h>
int calc_rate(uint64_t *rate, char val[], char mult[]) {
int rc = sscanf(val, "%" SCNu64 "%2s", rate, mult);
}
If you have both <inttypes.h> and <stdio.h> included, then the code fragment shown compiles cleanly. (You can't call sscanf() legally unless there's a prototype in scope.) That means the problem is in the code prior to what you are showing. Or it means that your compiler doesn't provide support for exactly 64-bit types, which is rather unlikely unless you're on a relatively obscure mainframe, or you aren't compiling in C99 or C11 mode.

Why cast is needed in printf?

To print a number of type off_t it was recommended to use the following piece of code:
off_t a;
printf("%llu\n", (unsigned long long)a);
Why the format string is not enough?
What will be the problem if it were not casted?
The format string doesn't tell the compiler to perform a cast to unsigned long long, it just tells printf that it's going to receive an unsigned long long. If you pass in something that's not an unsigned long long (which off_t might not be), then printf will simply misinterpret it, with surprising results.
The reason for this is that the compiler doesn't have to know anything about format strings. A good compiler will give you a warning message if you write printf("%d", 3.0), but what can a compiler do if you write printf(s, 3.0), with s being a string determined dynamically at run-time?
Edited to add: As Keith Thompson points out in the comments below, there are many places where the compiler can perform this sort of implicit conversion. printf is rather exceptional, in being one case where it can't. But if you declare a function to accept an unsigned long long, then the compiler will perform the conversion:
#include <stdio.h>
#include <sys/types.h>
int print_llu(unsigned long long ull)
{
return printf("%llu\n", ull); // O.K.; already converted
}
int main()
{
off_t a;
printf("%llu\n", a); // WRONG! Undefined behavior!
printf("%llu\n", (unsigned long long) a); // O.K.; explicit conversion
print_llu((unsigned long long) a); // O.K.; explicit conversion
print_llu(a); // O.K.; implicit conversion
return 0;
}
The reason for this is that printf is declared as int printf(const char *format, ...), where the ... is a "variadic" or "variable-arguments" notation, telling the compiler that it can accept any number and types of arguments after the format. (Obviously printf can't really accept any number and types of arguments: it can only accept the number and types that you tell it to, using format. But the compiler doesn't know anything about that; it's left to the programmer to handle it.)
Even with ..., the compiler does do some implicit conversions, such as promoting char to int and float to double. But these conversions are not specific to printf, and they do not, and cannot, depend on the format string.
The problem is you don't know how big an off_t is. It could be a 64 bit type or a 32 bit type (or perhaps something else). If you use %llu, and do not pass an (unsigned) long long type, you'll get undefined behavior, in practice it might just print garbage.
Not knowing how big it is, the easy way out is to cast it to the biggest reasonable type your system supports, e.g. a unsigned long long. That way using %llu is safe, as printf will receive an unsigned long long type because of the cast.
(e.g. on linux, the size of an off_t is 32 bit by default on a 32 bit machine, and 64 bit if you enable large file support via #define _FILE_OFFSET_BITS=64 before including the relevant system headers)
The signature of printf looks like this:
int printf(const char *format, ...);
The vararg... indicates that anything can follow, and by the rules of C, you can pass anything to printf as long as you include a format string. C simply does not have any constructs to describe any restrictions for the types of objects passed. This is why you must use casts so that the objects passed have exactly the needed type.
This is typical for C, it walks a line between rigidity and trusting the programmer. An unrelated example is that you may use char * (without const) to refer to string literals, but if you modify them, your program may crash.

why is strtof is always evaluating to HUGE_VAL?

What could be the issue here? It doesn't matter what number I choose for str, it is always 26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192.00
char *str = "2.6";
printf("%f\n", strtof(str, (char**)NULL));
//prints 26815615859885194199148049996411692254958731641184786755447122887443528060147093953603748596333806855380063716372972101707507765623893139892867298012168192.00
whole program:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char *str = "2.6";
printf("%f\n", strtof(str, NULL));
return 1;
}
compile with -Wall:
test4.c:7: warning: implicit declaration of function âstrtofâ
What platform are you building for/on? The warning that you say is being emitted:
test4.c:7: warning: implicit declaration of function âstrtofâ
indicates that the compiler doesn't know that strtof() returns a float, so it's going to push an int to the printf() call instead of a double. strtof() is normally declared in stdlib.h, which you're including. But it wasn't a standard function until C99, so the exact compiler platform (and configuration/options you're using) may affect whether it's being made available or not.
strtof is defined in C99 only. It may be that passing the option -std=c99 to the compiler will fix it since default GCC (-std=gnu89) includes only a few C99 features.
Another option is to use the C89-kosher strtod. Which is probably the better option in the long run, anyways. (When do you need singles except in exceptional circumstances?)
Perhaps you've forgotten to include the correct header(s)?
#include <stdlib.h>
#include <stdio.h>
int main() {
printf("%f\n", strtof("2.6", NULL));
return 0;
}
produces:
2.600000
for me...
Given your warnings, you should try adding -std=c99 to get the C99 standard definitions from the header. By default it will assume that the return value is an int and then try to convert that to a float. This will obviously be wrong. Alternatively you could simply supply your own, correct declaration for strtof().
As the others have said, you need -std=c99. But you can also use strtod() which is string to double, and you don't need -std=c99 for that.
I was having problems with strtof() on CentOS 5.5 with glibc 2.5 unless I used -std=c99, but strtod() worked perfectly.

Resources