3 Commits

Author SHA1 Message Date
wash fa9572d33a fx: iterator: return NULL value if iterator status is not SUCCESS 2026-05-30 20:19:47 +01:00
wash 8c0a31e19b meta: update rosetta support 2026-05-30 10:09:55 +01:00
wash a20306ae64 cmake: update package finder module 2026-05-29 20:45:46 +01:00
13 changed files with 459 additions and 133 deletions
+3 -1
View File
@@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.25)
project(fx C ASM)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake)
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include (TestBigEndian)
include(Templates)
include(Platform)
@@ -59,4 +59,6 @@ foreach (assembly ${fx_assemblies})
add_subdirectory(assemblies/${assembly})
endforeach (assembly)
if (fx_enable_tests)
add_subdirectory(test)
endif ()
+43 -108
View File
@@ -49,43 +49,37 @@ if (FX_STATIC)
set(_lib_suffix "-s")
endif ()
set(supported_components Core Ds Term Cmd Io Serial Compress)
set(components ${FX_FIND_COMPONENTS})
string(REPLACE ";" ", " supported_components_string_list "${supported_components}")
if (NOT components)
set(components ${supported_components})
endif ()
set(assemblies ${FX_FIND_COMPONENTS})
set(required_vars)
foreach (component ${components})
if (NOT "${component}" IN_LIST supported_components)
message(FATAL_ERROR "'${component}' is not a valid FX module.\nSupported modules: ${supported_components_string_list}")
endif ()
string(TOLOWER ${component} header_name)
set(lib_name ${header_name}${_lib_suffix})
if (NOT FX_${component}_INCLUDE_DIR)
find_path(FX_${component}_INCLUDE_DIR
NAMES fx/${header_name}.h ${FX_FIND_ARGS}
if (NOT FX_INCLUDE_DIR)
find_path(FX_INCLUDE_DIR
NAMES fx/misc.h ${FX_FIND_ARGS}
PATH_SUFFIXES include
PATHS ${FX_SEARCH_PATHS})
endif ()
if (NOT FX_${component}_LIBRARY)
find_library(FX_${component}_LIBRARY
NAMES fx-${lib_name} ${FX_FIND_ARGS}
set(required_vars FX_INCLUDE_DIR)
foreach (assembly ${assemblies})
string(TOLOWER ${assembly} header_name)
string(REPLACE "." "_" macro_name ${assembly})
string(TOUPPER ${macro_name} macro_name)
set(lib_name ${assembly}${_lib_suffix})
if (NOT ${macro_name}_LIBRARY)
find_library(${macro_name}_LIBRARY
NAMES ${lib_name} ${FX_FIND_ARGS}
PATH_SUFFIXES lib
PATHS ${FX_SEARCH_PATHS})
else ()
# on Windows, ensure paths are in canonical format (forward slahes):
file(TO_CMAKE_PATH "${FX_${component}_LIBRARY}" FX_${component}_LIBRARY)
file(TO_CMAKE_PATH "${${macro_name}_LIBRARY}" ${macro_name}_LIBRARY)
endif()
list(APPEND required_vars FX_${component}_INCLUDE_DIR FX_${component}_LIBRARY)
endforeach (component)
list(APPEND required_vars ${macro_name}_LIBRARY)
endforeach (assembly)
unset(FX_FIND_ARGS)
@@ -96,94 +90,35 @@ find_package_handle_standard_args(FX
if (FX_FOUND)
set(created_targets)
foreach (component ${components})
string(TOLOWER ${component} header_name)
set(lib_name ${header_name}${_lib_suffix})
foreach (assembly ${assemblies})
set(target_name ${assembly})
string(REPLACE "fx." "" target_name ${target_name})
string(SUBSTRING ${target_name} 0 1 target_name_prefix)
string(TOUPPER ${target_name_prefix} target_name_prefix)
string(SUBSTRING ${target_name} 1 -1 target_name_suffix)
set(target_name ${target_name_prefix}${target_name_suffix})
if(NOT TARGET FX::${component})
add_library(FX::${component} UNKNOWN IMPORTED)
set_target_properties(FX::${component} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FX_${component}_INCLUDE_DIR}")
target_compile_definitions(FX::${component} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
string(TOLOWER ${assembly} header_name)
string(REPLACE "." "_" macro_name ${assembly})
string(REPLACE "." "_" macro_name ${assembly})
string(TOUPPER ${macro_name} macro_name)
set(lib_name ${assembly}${_lib_suffix})
if (NOT TARGET FX::${target_name})
add_library(FX::${target_name} UNKNOWN IMPORTED)
set_target_properties(FX::${target_name} PROPERTIES
INTERFACE_INCLUDE_DIRECTORIES "${FX_INCLUDE_DIR}")
target_compile_definitions(FX::${target_name} INTERFACE _CRT_SECURE_NO_WARNINGS=1)
if (FX_STATIC)
target_compile_definitions(FX::${component} INTERFACE FX_STATIC=1)
target_compile_definitions(FX::${target_name} INTERFACE FX_STATIC=1)
endif ()
set_target_properties(FX::${component} PROPERTIES
set_target_properties(FX::${target_name} PROPERTIES
IMPORTED_LINK_INTERFACE_LANGUAGES "C"
IMPORTED_LOCATION "${FX_${component}_LIBRARY}")
set(created_targets ${created_targets} ${component})
IMPORTED_LOCATION "${${macro_name}_LIBRARY}")
set(created_targets ${created_targets} ${assembly})
endif ()
endforeach (component)
foreach (component ${created_targets})
if ("${component}" STREQUAL "Ds")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Ds' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Ds INTERFACE FX::Core)
endif ()
if ("${component}" STREQUAL "Term")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Term' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Term' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Term INTERFACE FX::Core FX::Ds)
endif ()
if ("${component}" STREQUAL "Serial")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Serial' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Serial INTERFACE FX::Core FX::Ds)
endif ()
if ("${component}" STREQUAL "Cmd")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Ds', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Term)
message(FATAL_ERROR "FX: Module 'Cmd' depends on 'Term', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Cmd INTERFACE FX::Core FX::Ds FX::Term)
endif ()
if ("${component}" STREQUAL "Io")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Io' depends on 'Core', which was not specified in find_package()")
endif ()
if (NOT TARGET FX::Ds)
message(FATAL_ERROR "FX: Module 'Io' depends on 'Ds', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Io INTERFACE FX::Core FX::Ds)
endif ()
if ("${component}" STREQUAL "Compress")
if (NOT TARGET FX::Core)
message(FATAL_ERROR "FX: Module 'Compress' depends on 'Core', which was not specified in find_package()")
endif ()
target_link_libraries(FX::Compress INTERFACE FX::Core FX::Ds)
endif ()
endforeach (component)
endforeach (assembly)
endif()
+2 -2
View File
@@ -19,7 +19,7 @@ function(get_platform_details)
elseif ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows")
set(system_name "win32")
else ()
message(FATAL_ERROR "Unsupported platform: ${CMAKE_SYSTEM_NAME}")
string(TOLOWER "${CMAKE_SYSTEM_NAME}" system_name)
endif ()
if ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "x86_64")
@@ -27,7 +27,7 @@ function(get_platform_details)
elseif ("${CMAKE_SYSTEM_PROCESSOR}" STREQUAL "arm64")
set(system_arch "aarch64")
else ()
message(FATAL_ERROR "Unsupported architecture: ${CMAKE_SYSTEM_PROCESSOR}")
string(TOLOWER "${CMAKE_SYSTEM_PROCESSOR}" system_arch)
endif ()
set(${arg_SYSTEM} ${system_name} PARENT_SCOPE)
+2
View File
@@ -47,6 +47,7 @@ function(add_fx_assembly)
target_compile_definitions(${assembly_target_name} PRIVATE ${def})
endforeach (def)
if (fx_enable_tests)
foreach (ns ${arg_NAMESPACES})
file(GLOB test_sources ${fx_source_root}/${ns}/test/*.c)
foreach (test_file ${test_sources})
@@ -57,6 +58,7 @@ function(add_fx_assembly)
target_link_libraries(${test_name} ${assembly_target_name})
endforeach (test_file)
endforeach (ns)
endif ()
set_target_properties(${assembly_target_name} PROPERTIES
FOLDER "${assembly_name}")
+95
View File
@@ -0,0 +1,95 @@
.extern memcpy
.type memcpy, @function
.global callvm_invoke_i
.type callvm_invoke_i, @function
# %rdi = (function ptr) impl
# %rsi = (struct callvm) context
callvm_invoke_i:
# save the stack frame pointer
push %rbp
mov %rsp, %rbp
# store function pointer for later
push %r12
push %r13
push %r14
push %r15
# move our parameters out of the way
mov %rdi, %r11
mov %rsi, %r12
# calculate the amount of stack space needed for the varargs
movq 32(%r12), %r13
shl $3, %r13
# allocate the stack space
push %rsp
sub %r13, %rsp
andq $0xFFFFFFFFFFFFFFF0, %rsp # re-align the stack
# copy the excess args to the stack
mov %rsp, %rdi
mov 160(%r12), %rsi
mov %r13, %rdx
call memcpy
# Next, set up the fixed integer arguments
movq 48(%r12), %rdi # int arg 0
movq 56(%r12), %rsi # int arg 1
movq 64(%r12), %rdx # int arg 2
movq 72(%r12), %rcx # int arg 3
movq 80(%r12), %r8 # int arg 4
movq 88(%r12), %r9 # int arg 5
# Finally, set up the fixed double arguments
movq 96(%r12), %xmm0 # double arg 0
movq 104(%r12), %xmm1 # double arg 1
movq 112(%r12), %xmm2 # double arg 2
movq 120(%r12), %xmm3 # double arg 3
movq 128(%r12), %xmm4 # double arg 4
movq 136(%r12), %xmm5 # double arg 5
movq 144(%r12), %xmm6 # double arg 6
movq 152(%r12), %xmm7 # double arg 7
# set the number of vararg double parameters
# as required by the ABI
mov 168(%r12), %rax
# call the function implementation
call *%r11
# Restore the stack pointer (deallocating the varargs buffer)
mov -40(%rbp), %rsp
# Restore callee-saved registers
pop %r15
pop %r14
pop %r13
pop %r12
# restore the saved stack frame
pop %rbp
ret
.global callvm_invoke_d
.type callvm_invoke_d, @function
# %rdi = (function ptr) impl
# %rsi = (struct callvm *) context
callvm_invoke_d:
jmp callvm_invoke_i
.global callvm_invoke_v
.type callvm_invoke_v, @function
# %rdi = (function ptr) impl
# %rsi = (struct callvm *) context
callvm_invoke_v:
jmp callvm_invoke_i
+243
View File
@@ -0,0 +1,243 @@
#include <fx/type.h>
#include <fx/value-type.h>
#include <platform/callvm.h>
#include <stdlib.h>
#if 0
switch (arg->v_type.t_primitive) {
case FX_VALUE_TYPE_DOUBLE:
break;
default:
callvm_push_int(&vm, (uintptr_t)arg->v_pointer);
break;
}
#endif
void callvm_reset(struct callvm *vm, unsigned int max_fixed_args)
{
vm->vm_arg_int_count = 0;
vm->vm_arg_double_count = 0;
vm->vm_arg_fixed = max_fixed_args;
vm->vm_arg_excess_count = 0;
vm->vm_double_excess_count = 0;
}
static void expand_excess(struct callvm *vm)
{
size_t new_capacity = vm->vm_arg_excess_max * 2;
if (!new_capacity) {
new_capacity = 4;
}
void *buf = realloc(
vm->vm_arg_excess,
new_capacity * sizeof *vm->vm_arg_excess);
if (!buf) {
return;
}
vm->vm_arg_excess = buf;
vm->vm_arg_excess_max = new_capacity;
}
static void push_excess(struct callvm *vm, uintptr_t value)
{
if (vm->vm_arg_excess_count + 1 > vm->vm_arg_excess_max) {
expand_excess(vm);
}
vm->vm_arg_excess[vm->vm_arg_excess_count++] = value;
vm->vm_arg_count++;
}
static void push_int(struct callvm *vm, uintptr_t value)
{
if (vm->vm_arg_int_count >= MAX_INT_ARGS) {
push_excess(vm, value);
return;
}
vm->vm_arg_int[vm->vm_arg_int_count++] = value;
vm->vm_arg_count++;
}
static void push_double(struct callvm *vm, double value)
{
if (vm->vm_arg_double_count >= MAX_DOUBLE_ARGS) {
push_excess(vm, *(uintptr_t *)&value);
return;
}
vm->vm_arg_double[vm->vm_arg_double_count++] = value;
vm->vm_arg_count++;
if (vm->vm_arg_count > vm->vm_arg_fixed) {
vm->vm_double_excess_count++;
}
}
void callvm_push(struct callvm *vm, const fx_value *value)
{
if (!fx_type_is_value_type(value->v_type)) {
push_int(vm, (uintptr_t)value->v_object);
return;
}
unsigned int value_type = __fx_type_get_value_type(value->v_type);
switch (value_type) {
case __FX_VALUE_TYPE_BOOL:
push_int(vm, value->v_bool);
break;
case __FX_VALUE_TYPE_I16:
push_int(vm, value->v_i16);
break;
case __FX_VALUE_TYPE_U16:
push_int(vm, value->v_u16);
break;
case __FX_VALUE_TYPE_I32:
push_int(vm, value->v_i32);
break;
case __FX_VALUE_TYPE_U32:
push_int(vm, value->v_u32);
break;
case __FX_VALUE_TYPE_I64:
push_int(vm, value->v_i64);
break;
case __FX_VALUE_TYPE_U64:
push_int(vm, value->v_u64);
break;
case __FX_VALUE_TYPE_IPTR:
push_int(vm, value->v_iptr);
break;
case __FX_VALUE_TYPE_UPTR:
push_int(vm, value->v_uptr);
break;
case __FX_VALUE_TYPE_SBYTE:
push_int(vm, value->v_sbyte);
break;
case __FX_VALUE_TYPE_BYTE:
push_int(vm, value->v_byte);
break;
case __FX_VALUE_TYPE_SHORT:
push_int(vm, value->v_short);
break;
case __FX_VALUE_TYPE_USHORT:
push_int(vm, value->v_ushort);
break;
case __FX_VALUE_TYPE_INT:
push_int(vm, value->v_int);
break;
case __FX_VALUE_TYPE_UINT:
push_int(vm, value->v_uint);
break;
case __FX_VALUE_TYPE_LONG:
push_int(vm, value->v_long);
break;
case __FX_VALUE_TYPE_ULONG:
push_int(vm, value->v_ulong);
break;
case __FX_VALUE_TYPE_LONGLONG:
push_int(vm, value->v_longlong);
break;
case __FX_VALUE_TYPE_ULONGLONG:
push_int(vm, value->v_ulonglong);
break;
case __FX_VALUE_TYPE_SIZE:
push_int(vm, value->v_size);
break;
case __FX_VALUE_TYPE_FLOAT:
push_double(vm, value->v_float);
break;
case __FX_VALUE_TYPE_DOUBLE:
push_double(vm, value->v_double);
break;
case __FX_VALUE_TYPE_CSTR:
push_int(vm, (uintptr_t)value->v_cstr);
break;
case __FX_VALUE_TYPE_POINTER:
push_int(vm, (uintptr_t)value->v_pointer);
break;
default:
break;
}
}
extern uintptr_t callvm_invoke_i(fx_function_impl impl, struct callvm *vm);
extern double callvm_invoke_d(fx_function_impl impl, struct callvm *vm);
extern void callvm_invoke_v(fx_function_impl impl, struct callvm *vm);
fx_value callvm_invoke(
struct callvm *vm,
fx_function_impl impl,
fx_type_id return_type)
{
if (!fx_type_is_value_type(return_type)) {
uintptr_t v = callvm_invoke_i(impl, vm);
fx_value result = {
.v_type = return_type,
.v_object = (fx_object *)v,
};
return result;
}
unsigned int value_type = __fx_type_get_value_type(return_type);
switch (value_type) {
case __FX_VALUE_TYPE_BOOL:
return FX_BOOL(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_I16:
return FX_I16(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_U16:
return FX_U16(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_I32:
return FX_I32(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_U32:
return FX_U32(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_I64:
return FX_I64(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_U64:
return FX_U64(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_IPTR:
return FX_IPTR(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_UPTR:
return FX_UPTR(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_SBYTE:
return FX_SBYTE(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_BYTE:
return FX_BYTE(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_SHORT:
return FX_SHORT(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_USHORT:
return FX_USHORT(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_INT:
return FX_INT(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_UINT:
return FX_UINT(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_LONG:
return FX_LONG(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_ULONG:
return FX_ULONG(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_LONGLONG:
return FX_LONGLONG(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_ULONGLONG:
return FX_ULONGLONG(callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_SIZE:
return FX_SIZE(callvm_invoke_i(impl, vm));
#if FX_ENABLE_FLOATING_POINT
case __FX_VALUE_TYPE_FLOAT:
return FX_FLOAT(callvm_invoke_d(impl, vm));
case __FX_VALUE_TYPE_DOUBLE:
return FX_DOUBLE(callvm_invoke_d(impl, vm));
#endif
case __FX_VALUE_TYPE_CSTR:
return FX_CSTR((const char *)callvm_invoke_i(impl, vm));
case __FX_VALUE_TYPE_POINTER:
return FX_POINTER((void *)callvm_invoke_i(impl, vm));
default:
return FX_VALUE_EMPTY;
}
return FX_VALUE_EMPTY;
}
@@ -0,0 +1,37 @@
#ifndef FX_REFLECTION_DARWIN_ARM64_CALLVM_H_
#define FX_REFLECTION_DARWIN_ARM64_CALLVM_H_
#include <fx/reflection/function.h>
#include <fx/value.h>
#include <stdint.h>
#define MAX_FIXED_ARGS ((unsigned int)-1)
#define MAX_DOUBLE_ARGS 8
#define MAX_INT_ARGS 6
/* dyn-dispatch.S depends on the layout of this struct */
struct callvm {
uint64_t vm_arg_int_count;
uint64_t vm_arg_double_count;
/* any args pushed after this limit is reached will be stored in the
* excess buffer. used for calling varargs functions */
uint64_t vm_arg_count, vm_arg_fixed;
uint64_t vm_arg_excess_count;
uint64_t vm_arg_excess_max;
uintptr_t vm_arg_int[MAX_INT_ARGS];
double vm_arg_double[MAX_DOUBLE_ARGS];
uintptr_t *vm_arg_excess;
uint64_t vm_double_excess_count;
};
extern void callvm_reset(struct callvm *vm, unsigned int max_fixed_args);
extern void callvm_push(struct callvm *vm, const fx_value *value);
extern fx_value callvm_invoke(
struct callvm *vm,
fx_function_impl impl,
fx_type_id return_type);
#endif
+8
View File
@@ -369,6 +369,7 @@ fx_status cstr_to_size(const char *in, size_t *out)
fx_status cstr_to_float(const char *in, float *out)
{
#if FX_ENABLE_FLOATING_POINT
char *ep;
float v = strtof(in, &ep);
if (*ep) {
@@ -377,10 +378,14 @@ fx_status cstr_to_float(const char *in, float *out)
*out = v;
return FX_SUCCESS;
#else
return FX_ERR_NOT_SUPPORTED;
#endif
}
fx_status cstr_to_double(const char *in, double *out)
{
#if FX_ENABLE_FLOATING_POINT
char *ep;
double v = strtod(in, &ep);
if (*ep) {
@@ -389,6 +394,9 @@ fx_status cstr_to_double(const char *in, double *out)
*out = v;
return FX_SUCCESS;
#else
return FX_ERR_NOT_SUPPORTED;
#endif
}
fx_status cstr_to_cstr(const char *in, const char **out)
+1 -1
View File
@@ -3,7 +3,7 @@
bool fx_wchar_is_number(fx_wchar c)
{
return iswdigit((wchar_t)c);
return (c >= '0' && c <= '9');
}
bool fx_wchar_is_alpha(fx_wchar c)
+8 -6
View File
@@ -51,9 +51,8 @@ enum fx_status fx_iterator_move_next(const fx_iterator *it)
{
enum fx_status status = FX_ERR_NOT_SUPPORTED;
fx_iterator_class *iface = fx_object_get_interface(
it,
FX_TYPE_ITERATOR);
fx_iterator_class *iface
= fx_object_get_interface(it, FX_TYPE_ITERATOR);
if (iface && iface->it_move_next) {
status = iface->it_move_next(it);
}
@@ -66,6 +65,10 @@ enum fx_status fx_iterator_move_next(const fx_iterator *it)
const fx_value *fx_iterator_get_value(const fx_iterator *it)
{
if (fx_iterator_get_status(it) != FX_SUCCESS) {
return NULL;
}
FX_CLASS_DISPATCH_VIRTUAL_0(
fx_iterator,
FX_TYPE_ITERATOR,
@@ -78,9 +81,8 @@ fx_status fx_iterator_erase(fx_iterator *it)
{
enum fx_status status = FX_ERR_NOT_SUPPORTED;
fx_iterator_class *iface = fx_object_get_interface(
it,
FX_TYPE_ITERATOR);
fx_iterator_class *iface
= fx_object_get_interface(it, FX_TYPE_ITERATOR);
if (iface && iface->it_erase) {
status = iface->it_erase(it);
}
+1 -1
View File
@@ -1,4 +1,4 @@
#include <fx/core/bitop.h>
#include <fx/bitop.h>
int fx_popcountl(long v)
{
+2
View File
@@ -29,11 +29,13 @@ int main(void)
printf("%02x", bytes[i % 16]);
}
#if FX_ENABLE_FLOATING_POINT
printf("\n\ngenerating %d random doubles:\n", NRAND_DOUBLES);
for (int i = 0; i < NRAND_DOUBLES; i++) {
double v = fx_random_next_double(&random);
printf(" %lf\n", v);
}
#endif
return 0;
}
+2 -2
View File
@@ -1,10 +1,10 @@
#include <stdarg.h>
#include <stdio.h>
static double another_function(int a, double b, int c)
static int another_function(int a, double b, int c)
{
printf("a=%d, b=%lf, c=%d\n", a, b, c);
return 1.2;
return 2;
}
static int test_function(int a, int b, int c, ...)