How to detect if printf will support %a? - c

I need to losslessly represent a double precision float in a string, and so I am using
sprintf(buf, "%la", x);
This works fine on my system, but when built on MinGW under Windows, gives a warning:
unknown conversion type character 'a' in format
I coded up a workaround for this case, but have trouble detecting when I should use the workaround -- I tried #if __STDC_VERSION__ >= 199901L, but it seems Gcc/MinGW defines that even if it doesn't support %a. Is there another macro I could check?

This doesn't answer the question "How to detect if printf will support %a?" in the general case, but you can modify your compiler installation so that %a is supported.
First of all , use mingw-w64. This is an up-to-date fork of MinGW. The original version of MinGW is not well maintained and does not fix bugs such as you are experiencing (preferring to blame Microsoft or something).
Using mingw-w64 4.9.2 in Windows 10, the following code works for me:
#include <stdio.h>
int main()
{
double x = 3.14;
printf("%a\n", x);
}
producing 0x1.91eb85p+1 which is correct. This is still deferring to the Microsoft runtime.
Your question mentions %la, however %a and %la are both the same and can be used to print either a float or a double argument.
If you want to print a long double, then the Microsoft runtime does not support that; gcc and MS use different sizes of long double. You have to use mingw-w64's own printf implementation:
#define __USE_MINGW_ANSI_STDIO 1
#include <stdio.h>
int main()
{
long double x = 3.14;
printf("%La\n", x);
}
which outputs 0xc.8f5c28f5c28f8p-2. This is actually the same number as 0x1.91eb85p+1 with more precision and a different placement of the binary point, it is also correct.

As jxh already suspected, MingW uses the MSVCRT LibC from Windows. The C99 support is not complete, especially some of the options of printf(3) like a are missing.

Related

scanf() and floating point numbers in Turbo C

I created a structure as:
typedef struct {
float real, img;
} cmplx;
and created a function as:
void input(cmplx *a){
scanf("%f + %f i", &a->real, &a->img); }
and called the function from main as:
cmplx a;
input(&a);
The execution stops when the scanf is reached. If floats are replaced by ints, the problem is solved. What is this behaviour? Is there a way I can use float for my problem?
The program was compiled on Turbo C, in MS-WINDOWS XP
It is hard to answer without knowing the error message that your program's execution stops with, but from your comment "is there any code i can write to tell compiler to link floating point library",
I suspect it may be this issue:
"Floating point formats not linked" is a Borland run-time error (Borland
C or C++, Turbo C or C++). Borland's compilers try to be smart and not
link in the floating- point (f-p) library unless you need it. Alas, they
all get the decision wrong. One common case is where you don't call any
f-p functions, but you have %f or other f-p formats in scanf() or
printf() calls. The cure is to call an f-p function, or at least force
one to be present in the link.
To do that, define this function somewhere in a source file but don't
call it:
static void forcefloat(float *p)
{
float f = *p;
forcefloat(&f);
}
It doesn't have to be in the module with the main program, as long as
it's in a module that will be included in the link.
If you have Borland C++ 3.0, the README file documents a slightly less
ugly work-around. Insert these statements in your program:
extern unsigned _floatconvert;
#pragma extref _floatconvert
Using this workaround, or a more modern compiler, will probably fix your issue.
Problem is with using years old C compiler like TurboC, as it works fine for me (I am Using DevC++)
check this discussion for similar issue

cross-platform printing of 64-bit integers with printf

In Windows, it is "%I64d". In Linux and Solaris, it is "%lld".
If I want to write cross-platform printfs that prints long long values: what is good way of doing so ?
long long ll;
printf(???, ll);
There are a couple of approaches.
You could write your code in C99-conforming fashion, and then supply system-specific hacks when the compiler-writers let you down. (Sadly, that's rather common in C99.)
#include <stdint.h>
#include <inttypes.h>
printf("My value is %10" PRId64 "\n", some_64_bit_expression);
If one of your target systems has neglected to implement <inttypes.h> or has in some other way fiendishly slacked off because some of the type features are optional, then you just need a system-specific #define for PRId64 (or whatever) on that system.
The other approach is to pick something that's currently always implemented as 64-bits and is supported by printf, and then cast. Not perfect but it will often do:
printf("My value is %10lld\n", (long long)some_64_bit_expression);
MSVC supports long long and ll starting Visual Studio 2005.
You could check the value of the _MSC_VER macro (>= 1400 for 2005), or simply don't support older compilers.
It doesn't provide the C99 macros, so you will have to cast to long long rather than using PRId64.
This won't help if you're using older MSVC libraries with a non-MSVC compiler (I think mingw, at least, provides its own version of printf that supports ll)
No on linux and solaris it is only incidentally that this is lld for a 64bit type. C99 prescribes simple (but ugly) macros to make these things portable PRId64. Since some windows compilers don't follow the standard you might be out of luck, there, unfortunately.
Edit: In your example you are using a different thing than a 64bit integer, namely a long long. This could well be 128 on some architectures. Here C99 has typedefs that guarantee you the minimum or exact width of the type (if they are implemented on the platform). These types are found with the inttypes.h header, namely int64_t for a fixe-width 64 bit type represented in two's complement. Maybe or maybe not your windows compiler has this.
As alternative you can use code like this:
uint64_t currentTimeMs = ...;
printf("currentTimeMs = 0x%08x%08x\n",
(uint32_t)(currentTimeMs >> 32),
(uint32_t)(currentTimeMs & 0xFFFFFFFF)
);
Or maybe:
printf("currentTimeMs = %u%09u\n",
(uint32_t)(currentTimeMs / 1000000000),
(uint32_t)(currentTimeMs % 1000000000)
);

Is using %zu correct syntax in a printf format string as shown in some C code found on Wikipedia?

I just found this code on Wikipedia.
Link: http://en.wikipedia.org/wiki/Sizeof#Use
The code:
/* the following code illustrates the use of sizeof
* with variables and expressions (no parentheses needed),
* and with type names (parentheses needed)
*/
char c;
printf("%zu,%zu", sizeof c, sizeof(int));
It states that: "The z prefix should be used to print it, because the actual size can differ on each architecture."
I tried it on my compiler, but it gives the following result:
zu,zu
Yes that syntax is correct (at least for C99). Looks like your compiler isn't set up to handle it though. Just take out the z and you'll probably be fine. To be correct, make sure your printf format specifiers match the size of the types. Turning on all the warnings your compiler will give you probably helps out in that respect.
Your quotation:
The z prefix should be used to print it, because the actual size can differ on each architecture
is referring to the fact that size_t (which is the type returned by the sizeof operator) can vary from architecture to architecture. The z is intended to make your code more portable. However, if your compiler doesn't support it, that's not going to work out. Just fiddle with combinations of %u, %lu, etc. until you get the output making sense.
The z length modifier was added to C in the C99 standard; you might have a compiler that doesn't support C99.
If your C compiler doesn't support that, you can probably treat the sizes as unsigned long:
printf("%lu,%lu", (unsigned long)sizeof c, (unsigned long)sizeof(int));
Yes, but it only works on C99-compliant compilers. From wikipedia:
z: For integer types, causes printf to expect a size_t sized integer argument.
Did you tell your compiler that you want it thinking with a C99 brain? There is probably a switch to do that. For instance, -std=c99 for gcc.
If your compiler does not support it, but you know others will, you can do a PRId64 style work around (disclaimer - PSEUDO CODE AHEAD ..):
#ifdef __SOME_KNOWN_C99_COMPILER
#define PORTUNSIGNED "zu"
#else
#define PORTUNSIGNED "u"
#endif
printf("%-11" PORTUNSIGNED " ways to skin a cat\n");
Its probably better to get a compiler that has functional support for c99, however.
I've made a test using gcc 4.0. It works with -std=c99

long integer problem

I'm a beginner at C, and using Turbo C++ compiler (16 bit).
In the software I'm writing, the maximum answer is around 32000. If I want a number larger than that, I use long int.
If I execute the following program:
#include <stdio.h>
void main()
{
long int x;
x=40000;
printf("%d", x);
}
Then I get an error that the constant value is long in function main().
How can I get an answer more that 32000 and get rid of this error?
also nw i change %d to %ld and use 40000L bt when i use unsigned integer then also i need to use 'l' with 40000//??
Use %ld in printf for the long int. %d is for int which only has 16 bits in your compiler. And for the error message, use x=40000L.
Change long to unsigned, 40000 will fit in unsigned int.
Assuming you're on windows, the best solution to this is to target a 32 or 64-bit platform. 16-bit programs won't even run on 64-bit versions of windows; you should really upgrade.
Microsoft has a free version of Visual Studio: Visual C++ Express Edition. This is an excellent option also because it comes with a full IDE.
Gcc is also available for windows in the form of Mingw. Unfortunately, mingw itself does not release ready-to-use compilers, but others do, such as equation.com or TDM.
Perhaps brushing up on variadic formatting might help :) By the time you (or the printf() subsystem) actually gets to expanding variadic arguments, its assumed that you know what type they are.
This not only goes for printf, but any other function that employs va_*() or v*printf() when discussing printf. Don't lose track of your types.
Also, keep track of signedness to avoid unexpected results.
In other words, by the time you call printf(), or anything else accepting an elipsis, be sure of what you are passing. This isn't limited to printf(), in fact venturing beyond that will often not produce compiler warnings.

How am I incorrectly using the round() function in C?

I'm getting unexpected results from the round() and roundf() functions in the math.h library. Here is the sample code:
#include <stdio.h>
#include <math.h>
int main(void)
{
float f;
double d;
/* Note man page says that roundf() returns a float
and round() returns a double */
f = roundf(1.2);
d = round(1.2);
printf("%f\n", f);
printf("%lf\n", d);
return 0;
}
When I complie and run the program I get:
gcc -lm round.c
./a.out
288.000000
524288.000000
Wierd huh?
Update: Along with the answers I've confirmed that the code works properly on a newer complier. (I think %lf is not the correct printf specifier but that doesn't affect the end result in this case.) I'll need to figure out why may compiler is behaving this way because I have running code that uses round() and has been compiler on the same machine. I'll update the post when I figure it out.
gcc -v
Reading specs from /usr/lib/gcc-lib/i386-slackware-linux/2.95.3/specs
gcc version 2.95.3 20010315 (release)
You can fail if you compile the code without telling gcc to compile with C99 mode (-std=c99) and tell it not to know about "special builtin" functions (using -fno-builtin). Then it assumes that your round/roundf function is defined as
int round();
int roundf();
Because in pre-C99 times there were no such functions yet, so it does not have a declaration and implicitly declares them then. And this will obviously fail, because the call-side treats the return value as an int, while the callee side (in the definition of those functions in the linked library) returns a float. I get these results for example:
[js#HOST2 cpp]$ ./a.out
1065353216.000000
-1048576.000000
[js#HOST2 cpp]$
Not that you think now that you could cast the return value to a float and be OK. Well, it's worse. The return value is not even guaranteed to have anything to do with the float returned. The call-side reads from a place that it knows where integers are returned. But your compiler may return floats in another place (say, in a floating pointer register) from the callee side. The above could actually have done anything, including aborting the program because it behaves in an undefined manner.
So, what can you do to make it work? Pass the compiler the std=c99 flag or use other ways to round (floor is one of them) which do not require those functions
gcc -std=c99 test.c -lm
See the manpage of man 3 round. However, if you have a very old GCC - i'm not sure whether it supports enough of C99 to have that switch. Look into the feature test macros described in the manpage of round then.
When I compile and run this exact code (under gcc on cygwin) I get:
$ ./a.exe
1.000000
1.000000
How new is your compiler? A compiler bug is all I can think of, as gcc -Wall gives no warnings either.
To add some further information this forum thread seems to show changing compiler to a newer version fixes it. If this doesn't work for you you'll need to give more details of compiler and OS, but given this seems to work for other people on three different platforms looks like your compiler is at fault.
To add to the chorus of approvals, this works fine for me (OS X Leopard using gcc).
Out of curiosity, do you need to use the -lm flag? I didn't the first time, and I did the second time, and there was no difference, but that's because libm.dylib and libc.dylib are symbolic links to the same library on OS X. Perhaps your libm is broken or something? Do you need to link to libm or not? I would think that the math.h functions would be part of libc...?
EDIT:
Before you do any of that, try using this instead:
float f = 0;
double d = 0;
I don't think that should change anything, but if it does, I win.
One more "works on my machine" on Ubuntu with gcc version 4.3.2.
$ ./a.out
1.000000
1.000000
I do get a couple of warnings when I compile, though.
$ gcc -lm round.c
round.c: In function ‘main’:
round.c:11: warning: incompatible implicit declaration of built-in function ‘roundf’
round.c:12: warning: incompatible implicit declaration of built-in function ‘round’
litb was on the right track. -std=c99 didn't work but adding #define _ISOC99_SOURCE worked. So the code looks like:
#define _ISOC99_SOURCE
#include <stdio.h>
#include <math.h>
int main(void)
{
...
This obviously doesn't help but the code looks and runs as expected for me. Everything seems fine.
Looks like you're using it right, describe your environment some?

Categories

Resources