C file functions in QB64 ???
#1
I wonder if it's possible to get the C file functions working in QB64, specifically fopen, fprintf and fclose
I tried the following but it won't compile
Code: (Select All)
Type iobuf
    ptr As _Offset 'zstring ptr
    cnt As Long
    bas As _Offset 'zstring ptr
    flag As Long
    file As Long
    charbuf As Long
    bufsiz As Long
    tmpfname As _Offset 'zstring ptr
End Type

Declare Library
    Function fopen%& (file_name As String, mode As String)
    Function fclose& (file_ptr As _Offset)
    Function fprintf& (file_ptr As _Offset, frmt As String, st As String)
End Declare

Dim As _Offset fp
Dim As String fln, md, frmt, text
Dim As Long status

fln = "fopen-test.txt" + Chr$(0)
md = "w" + Chr$(0)
frmt = "%s\n" + Chr$(0)
text = "hello world" + Chr$(0)

fp = fopen(fln, md)
status = fprintf(fp, frmt, text)
Print "status = fprintf(fp, frmt, text) = "; status
status = fclose(fp)

the compiler log follows
Quote:internal\c\c_compiler\bin\c++.exe -O2 -w -std=gnu++11 -DGLEW_STATIC -DFREEGLUT_STATIC -Iinternal\c\libqb/include -Iinternal\c/parts/core/src/ -Iinternal\c/parts/core/glew/include/ -DDEPENDENCY_NO_SOCKETS -DDEPENDENCY_NO_PRINTER -DDEPENDENCY_NO_ICON -DDEPENDENCY_NO_SCREENIMAGE internal\c/qbx.cpp -c -o internal\c/qbx.o
In file included from internal\c/qbx.cpp:2333:
internal\c/../temp/main.txt: In function 'void QBMAIN(void*)':
internal\c/../temp/main.txt:29:35: error: cannot convert 'intptr_t*' {aka 'long long int*'} to 'FILE*' {aka '_iobuf*'}
  29 | *__LONG_STATUS=(  int32  )fprintf(__OFFSET_FP,(char*)(__STRING_FRMT)->chr,(char*)(__STRING_TEXT)->chr);
      |                                  ^~~~~~~~~~~
      |                                  |
      |                                  intptr_t* {aka long long int*}
In file included from internal\c\libqb/include/audio.h:21,
                from internal\c/qbx.cpp:1:
D:/QB64pe-3.6.0+/internal/c/c_compiler/x86_64-w64-mingw32/include/stdio.h:357:20: note:  initializing argument 1 of 'int fprintf(FILE*, const char*, ...)'
  357 | int fprintf (FILE *__stream, const char *__format, ...)
      |              ~~~~~~^~~~~~~~
internal\c/../temp/main.txt:48:34: error: cannot convert 'intptr_t*' {aka 'long long int*'} to 'FILE*' {aka '_iobuf*'}
  48 | *__LONG_STATUS=(  int32  )fclose(__OFFSET_FP);
      |                                  ^~~~~~~~~~~
      |                                  |
      |                                  intptr_t* {aka long long int*}
D:/QB64pe-3.6.0+/internal/c/c_compiler/x86_64-w64-mingw32/include/stdio.h:615:28: note:  initializing argument 1 of 'int fclose(FILE*)'
  615 |  int __cdecl fclose(FILE *_File);
      |                      ~~~~~~^~~~~
mingw32-make: *** [Makefile:410: internal\c/qbx.o] Error 1

I know that QB64 has file functions but I have a reason to want the C file functions

<edit>
fopen works, it's the other two functions that fail
Reply
#2
using the msvcrt.dll helps to avoid type clashes, and although it compiles, it crashes
Code: (Select All)
Type file
    ptr As _Offset 'zstring ptr
    cnt As Long
    bas As _Offset 'zstring ptr
    flag As Long
    file As Long
    charbuf As Long
    bufsiz As Long
    tmpfname As _Offset 'zstring ptr
End Type

Declare Dynamic Library "msvcrt"
    Function fopen%& (file_name As String, mode As String)
    Function fclose& (file_ptr As _Offset)
    Function fprintf& (file_ptr As _Offset, frmt As String, st As String)
End Declare

Dim As _Offset fp
Dim As String fln, md, frmt, text
Dim As Long status

'fp = _Offset(file)

fln = "fopen-test.txt" + Chr$(0)
md = "w" + Chr$(0)
frmt = "%s\n" + Chr$(0)
text = "hello world" + Chr$(0)

fp = fopen(fln, md)
Print "fp = fopen(fln, md) = "; fp
status = fprintf(fp, frmt, text)
status = fclose(fp)
Reply
#3
There's a couple issues. The big one is the lack of
Byval
on your
file_ptr
parameters to
fprintf()
and
fclose()
. Pass-by-reference is the default so QB64 will actually pass the address of the
_Offset
rather than the
_Offset
value itself, leading to the explosions you're encountering. If you instead use
byval file_ptr As _Offset
then it might work.

The other issues is the types in the C++ function definitions.
fprintf()
and
fclose()
take a
FILE *
as their first argument, but an
_Offset
is an
intptr_t
so you cannot pass that as a
FILE *
without a cast (and there's no way to insert the cast as QB64 won't do it for you). The solution here is to use either
Declare Dynamic Library
or (preferably)
Declare CustomType Library
, both of those cause QB64 to generate its own C++ definitions for the functions listed in the
Declare Library
section based on the types you define, so the types you provide will always match. The big catch with this is that it also means there will be no type-checking by C++ to ensure you're actually passing the right thing, so it's best to use regular
Declare Library
for any functions where it's possible for you to provide the correct types directly (like
fopen()
).
Reply
#4
maybe (but just maybe) it would work using the H file, because FILE * could perhaps be defined somehow in the H file. The same problem was with glQuadric in OpenGL, which was then solved by Ashish using the H file, which I subsequently only expanded . See how he called *quad here. I assume that FILE * should also be called in a very similar way.

Code: (Select All)
/*
  @Author
  Ashish Kushwaha
*/


GLUquadric *quad;

//initialize earth
void initEarth ()
{    
    quad = gluNewQuadric();
    return;
}
//draws earth
void drawEarth()
{
    gluQuadricTexture(quad, 1);
    gluSphere(quad, 3.5, 30, 30);
    return;
}


And I confirm that the absence of BYVAL reliably crashes every program, I had a problem with that too, adding BYVAL fixed everything.


Reply
#5
Hi DSMan195276
you were right, byval fixed it Smile
I should have seen it, it was there right in front of me Angry
when you use a DLL you are not bothered by type correctness, just as long as the data will fit in the type it works
that's why in my second attempt I used Declare Dynamic Library "msvcrt"
thanks for opening my eyes Smile
Code: (Select All)
Declare Dynamic Library "msvcrt"
    Function fopen%& (file_name As String, mode As String)
    Function fclose& (ByVal file_ptr As _Offset)
    Function fprintf& (ByVal file_ptr As _Offset, frmt As String, st As String)
    Function fread~&& (buff As String, Byval size As _Unsigned _Integer64, Byval count As _Unsigned _Integer64, Byval file_ptr As _Offset)
End Declare

Dim As _Offset fp
Dim As String fln, md, frmt, text
Dim As Long status

fln = "fopen1-test.txt" + Chr$(0)
md = "w" + Chr$(0)
frmt = "%s" + Chr$(13) + Chr$(10) + Chr$(0) '\n didn't work but + Chr$(13) + Chr$(10) does work
text = "hello world" + Chr$(0)

fp = fopen(fln, md)
status = fprintf(fp, frmt, text)
status = fclose(fp)

md = "r" + Chr$(0)
text = Space$(64) + Chr$(0)
fp = fopen(fln, md)
status = fread(text, 1, 64, fp)
Print text

it displays hello world
Reply
#6
Quote:it displays hello world
I don't see any of that on me. However, the created text file with the correct content is available.

Unfortunately, the attempt to display the text of the file on the screen did not work either: fprintf(stdout, ". . .", x, y);

[Image: Aufruf-C-Funktionen.jpg]
Reply
#7
hello Kernelpanic Smile
use the code right above your post, it should work as is
Reply
#8
@Kernelpanic
I think I know why you are having a problem, you must be using the 32-bit version of QB64
if that's the case then try the code below

for 32-bit QB64
Code: (Select All)
Declare Dynamic Library "msvcrt"
    Function fopen%& (file_name As String, mode As String)
    Function fclose& (ByVal file_ptr As _Offset)
    Function fprintf& (ByVal file_ptr As _Offset, frmt As String, st As String)
    Function fread~& (buff As String, Byval size As _Unsigned long, Byval count As _Unsigned long, Byval file_ptr As _Offset)
End Declare

Dim As _Offset fp
Dim As String fln, md, frmt, text
Dim As Long status

fln = "fopen1-test.txt" + Chr$(0)
md = "w" + Chr$(0)
frmt = "%s" + Chr$(13) + Chr$(10) + Chr$(0) '\n didn't work but + Chr$(13) + Chr$(10) does work
text = "hello world" + Chr$(0)

fp = fopen(fln, md)
status = fprintf(fp, frmt, text)
status = fclose(fp)

md = "r" + Chr$(0)
text = Space$(64) + Chr$(0)
fp = fopen(fln, md)
status = fread(text, 1, 64, fp)
Print text
Reply
#9
I'd recommend putting the 64 bit and 32 bit code into their own $IF blocks that way no matter what architecture someone is on, the file will dynamically be ready to compile for their system, whether 32 or 64.
So something like
$IF 32BIT THEN
'insert 32 bit specific code
$ELSE
'insert 64 bit specific code
$END IF
Schuwatch!
Yes, it's me. Now shut up.
Reply
#10
Quote:I think I know why you are having a problem, you must be using the 32-bit version of QB64
if that's the case then try the code below
The second version works, also with the 64 bit version.

What have you changed? At first glance I don't see it, maybe at second glance.

[Image: Aufruf-C-Funktionen-V2.jpg]
Reply




Users browsing this thread: 3 Guest(s)