4

I'm attempting to compile a program in C for the ZX Spectrum using Z88DK. However, I'm facing an issue when trying to use printf to print out the value of a float.

The code I'm trying to compile:

#include <stdio.h>
#include <math.h>

int main()
{
    printf("Hello World\n");
    printf("Testing float...\n");
    double pi = 3.141;
    printf("Pi is: %f\n", pi);
    return 1;
}

and I'm compiling with:

zcc +zx -lm -create-app -startup=1 -clib=new  main.c -o floatTest

The program compiles however nothing is printed on the screen where the value of the float should be. Here is a screenshot of the Fuse emulator output of the program above.

Fuse emulator screenshot of output of program above

I've tried using float and double, adding different formatting options like %06.2f, but nothing seems to work. I can't get anything to display on the screen.

I'm stuck on how to resolve this issue and any help would be appreciated!

  • 1
    Does the hardware actually have an FPU? If not, have you enabled any emulation layer when compiling the program? – Ruslan Feb 25 at 12:53
  • 3
    @cobbm: You have checked that you can print int with %d, char with %c and string with %s, haven't you? Checking that other parts of printf work is wise before you get into floats. – John Dallman Feb 25 at 13:33
  • 2
    I don't know about that specific platform, but in the toolchain for the ARM-based MCU that I'm writing code for right now, I have an option to enable "floating point printf" or not. If I choose the "not" option, then the %...f printf directive behaves exactly as you describe: It consumes one float-size argument, and it outputs nothing at all. Maybe your library works the same way. Maybe you even have the same option somewhere. – Solomon Slow Feb 25 at 15:03
  • 1
    Various compilers do not print FP well unless some FP math is done. Try double pi = 3.141; double m = pi/100.0; printf("Pi is: %f\n", pi); or other such code. – chux - Reinstate Monica Feb 25 at 15:31
  • 1
    Lol, FPU on a speccy. It did have some fp routines in the rom afaik. – user1095108 May 4 at 9:00
9

Assuming you use the SDCC backend: SDCCs printf does not include float support by default. You need to recompile the z80.lib library with USE_FLOATS=1 set in printf_large.c

| improve this answer | |
3

The z88dk does not differentiate between float or double, at least with its own compiler; the SDCC backend is another beast.

Some years ago I played around with the z88dk, targetting the ZX81. I was kind of disappointed that its implementation of printf() does not support floating point data types. It might have changed in the meantime, but I'm afraid that rather not. A quick look through the Wiki does not reveal anything, even though you might like to check this yourself.

Actually there are different implementations of printf(). The compiler decides by introspection of your source which one to use.

| improve this answer | |
3

With newlib it seems you have to explicitly state that you want to include the floating point formatter with a pragma, just add:

#pragma printf %f

to the source code. That way it will work with both sccz80 and zsdcc as the compiler. By default the integer converters are included.

sccz80 does format detection, but this is only picked up the classic library. So if you want to use zsdcc and classic you'll have to specify them again.

Likewise for scanf the set of converters can be configured using

#pragma scanf converters

There's some documentation on z88dk wiki here: https://github.com/z88dk/z88dk/wiki/Classic--Pragmas#configuring-printf-and-scanf-converters

| improve this answer | |
0

Although the printf implementation z88dk's classic C library doesn't support outputting floats, it does have in its stdlib.h a mostly undocumented function named ftoa that will convert a float to a string:

https://github.com/z88dk/z88dk/blob/master/libsrc/math/genmath/ftoa.c

| improve this answer | |
  • Classic has actually supported printing floats for around 20+ years. As it happens, that ftoa() routine (and the corresponding ftoe()) are the routines that are used internally. The format handler is here: github.com/z88dk/z88dk/blob/master/libsrc/stdio/… which is a bit spaghetti-like due to supporting the two different argument passing conventions and the 3 different float sizes currently supported. – suborb May 22 at 22:14
  • @suborb perhaps, but it doesn't work for me. Using the %f specifier just prints a literal "f" character in the output, no matter what value I supply in the documented pragma. – Paul Humphreys May 24 at 19:32
  • Don't suppose it's a multi-file project? In which case this thread explains how to sort it out: z88dk.org/forum/viewtopic.php?pid=18615#p18615 if not, raise an issue and I'll get it sorted. – suborb May 25 at 20:17
  • @suborb It is, and I'm also using --no-crt as I'm working with a custom memory layout. I tried the instructions on the forum but those didn't work for me either – Paul Humphreys May 28 at 19:55
  • 1
    You're well off-piste using a custom CRT. No wonder it's not working as intended! You'll need to take a copy of libsrc/stdio/__printf_format_table.asm and add to your project after editing it to include the formatters you need. The standard CRTs handle it automatically via lib/crt/classic/crt_runtime_selection.asm – suborb May 29 at 20:17

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.