hi
Please could you add a keyword to disable the check of parameters number like "..." with C
or a option to disable the "incorrect number of parameters" error. I highly need dat.
allow variable arguments
Re: allow variable arguments
And how you want access this undefined (name and type) parameters?
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Lizard - Script language for symbolic calculations and more ― Typeface - Sprite-based font include/module
Re: allow variable arguments
I think this will never come, but ...?
Here is a workaround: http://www.purebasic.fr/english/viewtop ... 80#p376680
Here is a workaround: http://www.purebasic.fr/english/viewtop ... 80#p376680
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.

Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.

Re: allow variable arguments
you must pick the memory between the first parameters and the first variable. here is a exampleSTARGÅTE wrote:And how you want access this undefined (name and type) parameters?
Code: Select all
procedure printf ( *text, ... )
define *paramlist_start
define *paramlist_end
*paramlist_start = @*text + sizeof( int ) ; get the stack address of the undefined parameters
*paramlist_end = @*paramlist_start - *paramlist_start
Code: Select all
; %d or %i
arg = peeki( *paramlist_start )
*paramlist_start + sizeof( int ) ; going to the next argument
; %c
arg = peekc( *paramlist_start )
*paramlist_start + sizeof( char ) ; going to the next argument
...
; more request than arguments ?
if( *paramlist_start > *paramlist_end )
debug "overflow"
endif
the main purpose of my request is to be able to import C function which use var args, this is not hard to implement just disable thets-soft wrote:I think this will never come, but ...?
Here is a workaround: http://www.purebasic.fr/english/viewtop ... 80#p376680
error check if the last defined argument is "..." (c style) or maybe a new type/keyword ?
EDIT: more about
http://www.cplusplus.com/reference/clibrary/cstdarg/
from microsoft libc
stdarg.h:
Code: Select all
/***
*stdarg.h - defines ANSI-style macros for variable argument functions
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* This file defines ANSI-style macros for accessing arguments
* of functions which take a variable number of arguments.
* [ANSI]
*
* [Public]
*
****/
#pragma once
#ifndef _INC_STDARG
#define _INC_STDARG
#if !defined(_WIN32)
#error ERROR: Only Win32 target supported!
#endif
#include <vadefs.h>
#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end
#endif /* _INC_STDARG */
Code: Select all
/***
*vadefs.h - defines helper macros for stdarg.h
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
*Purpose:
* This is a helper file for stdarg.h
*
* [Public]
*
****/
#pragma once
#ifndef _INC_VADEFS
#define _INC_VADEFS
#if !defined(_WIN32)
#error ERROR: Only Win32 target supported!
#endif
/*
* Currently, all MS C compilers for Win32 platforms default to 8 byte
* alignment.
*/
#undef _CRT_PACKING
#define _CRT_PACKING 8
#pragma pack(push,_CRT_PACKING)
#ifdef __cplusplus
extern "C" {
#endif
#if !defined(_W64)
#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86))
#define _W64 __w64
#else
#define _W64
#endif
#endif
#ifndef _UINTPTR_T_DEFINED
#ifdef _WIN64
typedef unsigned __int64 uintptr_t;
#else
typedef _W64 unsigned int uintptr_t;
#endif
#define _UINTPTR_T_DEFINED
#endif
#ifndef _VA_LIST_DEFINED
#ifdef _M_CEE_PURE
typedef System::ArgIterator va_list;
#else
typedef char * va_list;
#endif /* _M_CEE_PURE */
#define _VA_LIST_DEFINED
#endif
#ifdef __cplusplus
#define _ADDRESSOF(v) ( &reinterpret_cast<const char &>(v) )
#else
#define _ADDRESSOF(v) ( &(v) )
#endif
#if defined(_M_IA64) && !defined(_M_CEE_PURE)
#define _VA_ALIGN 8
#define _SLOTSIZEOF(t) ( (sizeof(t) + _VA_ALIGN - 1) & ~(_VA_ALIGN - 1) )
#define _VA_STRUCT_ALIGN 16
#define _ALIGNOF(ap) ((((ap)+_VA_STRUCT_ALIGN - 1) & ~(_VA_STRUCT_ALIGN -1)) \
- (ap))
#define _APALIGN(t,ap) (__alignof(t) > 8 ? _ALIGNOF((uintptr_t) ap) : 0)
#else
#define _SLOTSIZEOF(t) (sizeof(t))
#define _APALIGN(t,ap) (__alignof(t))
#endif
#if defined(_M_CEE)
extern void __cdecl __va_start(va_list*, ...);
extern void * __cdecl __va_arg(va_list*, ...);
extern void __cdecl __va_end(va_list*);
#define _crt_va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \
__alignof(v), _ADDRESSOF(v)) )
#define _crt_va_arg(ap,t) ( *(t *)__va_arg(&ap, _SLOTSIZEOF(t), \
_APALIGN(t,ap), (t *)0) )
#define _crt_va_end(ap) ( __va_end(&ap) )
#elif defined(_M_IX86)
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_IA64)
#ifdef __cplusplus
extern void __cdecl __va_start(va_list*, ...);
#define _crt_va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \
_ADDRESSOF(v)) )
#else
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _SLOTSIZEOF(v) )
#endif
#define _crt_va_arg(ap,t) (*(t *)((ap += _SLOTSIZEOF(t)+ _APALIGN(t,ap)) \
-_SLOTSIZEOF(t)))
#define _crt_va_end(ap) ( ap = (va_list)0 )
#elif defined(_M_AMD64)
extern void __cdecl __va_start(va_list *, ...);
#define _crt_va_start(ap, x) ( __va_start(&ap, x) )
#define _crt_va_arg(ap, t) \
( ( sizeof(t) > sizeof(__int64) || ( sizeof(t) & (sizeof(t) - 1) ) != 0 ) \
? **(t **)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) \
: *(t *)( ( ap += sizeof(__int64) ) - sizeof(__int64) ) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#else
/* A guess at the proper definitions for other platforms */
#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap) ( ap = (va_list)0 )
#endif
#ifdef __cplusplus
}
#endif
#pragma pack(pop)
#endif /* _INC_VADEFS */
Re: allow variable arguments
but wouldn't this imply that it's taking a quad?
/*
* Currently, all MS C compilers for Win32 platforms default to 8 byte
* alignment.
*/
Windows 11, Manjaro, Raspberry Pi OS


Re: allow variable arguments
dunno about this alignment i just tried on vc2010 x86 and there is no 8b alignment by default
to check i did this
produce
to check i did this
Code: Select all
#include <stdio.h>
#include <tchar.h>
void teststackalignment(int a, short b, __int8 c, __int64 d, float e, char f)
{
printf("stack alignment:\na at %0x\n", &a);
printf("b at %0x (+%i)\n", &b, (int)&b-(int)&a);
printf("c at %0x (+%i)\n", &c, (int)&c-(int)&b);
printf("d at %0x (+%i)\n", &d, (int)&d-(int)&c);
printf("e at %0x (+%i)\n", &e, (int)&e-(int)&d);
printf("f at %0x (+%i)\n", &f, (int)&f-(int)&e);
}
struct testalign {
int a;
short b;
__int8 c;
__int64 d;
float e;
char f;
};
int _tmain(int argc, _TCHAR* argv[])
{
struct testalign strtest;
printf("structure alignment:\na at %0x\n", &strtest.a);
printf("b at %0x (+%i)\n", &strtest.b, (int)&strtest.b-(int)&strtest.a);
printf("c at %0x (+%i)\n", &strtest.c, (int)&strtest.c-(int)&strtest.b);
printf("d at %0x (+%i)\n", &strtest.d, (int)&strtest.d-(int)&strtest.c);
printf("e at %0x (+%i)\n", &strtest.e, (int)&strtest.e-(int)&strtest.d);
printf("f at %0x (+%i)\n------------\n", &strtest.f, (int)&strtest.f-(int)&strtest.e);
teststackalignment(55,(short)88,(__int8)678,(__int64)487,85.5f,85);
printf("\n_CRT_PACKING = %i\n",_CRT_PACKING);
system("PAUSE");
return 0;
}
structure alignment:
a at 41fec4
b at 41fec8 (+4)
c at 41feca (+2)
d at 41fecc (+2)
e at 41fed4 (+8)
f at 41fed8 (+4)
------------
stack alignment:
a at 41fdd8
b at 41fddc (+4)
c at 41fde0 (+4)
d at 41fde4 (+4)
e at 41fdec (+8)
f at 41fdf0 (+4)
_CRT_PACKING = 8
Press any key to continue . . .
-
- Enthusiast
- Posts: 334
- Joined: Mon Feb 04, 2013 5:28 pm
Re: allow variable arguments
+ 1, as someone would say
Currently we can import most C functions at compile time with ImportC and dynamically with PrototypeC + GetFunction().
Would be useful to have the ability to properly import C functions like printf().
Many C libraries export functions like that.
PB could use something like "..." as the last parameter of a function prototype/import to indicate a variable number of parameters.
When generating the code, the compiler could check how many parameters the caller is using and simply push that number of parameters on the stack, to remove them later.
It shouldn't be a problem to implement this one.
At the moment we must use multiple prototype definitions, each one with a different number of parameters, and invoke a different function each time as needed. Not nice.
Or we can use CallCFunctionFast(). This one supports a variable number of parameters but it's not compatible with prototypes or ImportC.
To have the ability to specify a variable number of parameters for PB procedures would be a plus, practically mixing cdecl and stdcall conventions as needed.
But even just the importing bit would be a nice step, after all one of the cardinal features of cdecl is the ability to specify a variable number of parameters, so if you implement an ImportC and a PrototypeC how could you not support that ?
Currently we can import most C functions at compile time with ImportC and dynamically with PrototypeC + GetFunction().
Would be useful to have the ability to properly import C functions like printf().
Many C libraries export functions like that.
PB could use something like "..." as the last parameter of a function prototype/import to indicate a variable number of parameters.
When generating the code, the compiler could check how many parameters the caller is using and simply push that number of parameters on the stack, to remove them later.
It shouldn't be a problem to implement this one.
At the moment we must use multiple prototype definitions, each one with a different number of parameters, and invoke a different function each time as needed. Not nice.
Or we can use CallCFunctionFast(). This one supports a variable number of parameters but it's not compatible with prototypes or ImportC.
To have the ability to specify a variable number of parameters for PB procedures would be a plus, practically mixing cdecl and stdcall conventions as needed.
But even just the importing bit would be a nice step, after all one of the cardinal features of cdecl is the ability to specify a variable number of parameters, so if you implement an ImportC and a PrototypeC how could you not support that ?
Re: allow variable arguments
Don't hold your breath. The way PB currently handles local variables would force a rewrite of its local-variable handling. Instead of using a Frame Pointer (as required for variable arguments), PB references directly from the stack. This leaves an extra register for other uses, but means you cannot push or pop the stack without corrupting the offset reference (as required for variable arguments).
...maybe when the llvm port is implemented? (2020?)
...maybe when the llvm port is implemented? (2020?)