I need to solve one problem in a virgin ANSI C (1989).
I have some pointer (void *func) to function with (int n) double parameters, and have array double values[] with n numbers. So I want to run my function with n param that are located in value.
For example, I have function:
double hypotenuse(double x, double y, double z);
so
void *func = (void *)hypotenuse; double values[3] = {5, 4, 3}; int n = 3;
and I want to do something like this:
func(n, values);
The problem is that I can't change the prototypes of the functions,
so I need to do this somehow (maybe some macros?).
The main problem is that you have to cast the pointer differently depending on the number of argument (i.e. depending on the n variable).
One way is to use a wrapper-function containing a switch statement for the argument number:
double wrapper(void *func, double args[], int n)
{
switch (n)
{
case 0:
return ((double (*)(void)) func)();
case 1:
return ((double (*)(double)) func)(args[0]);
case 2:
return ((double (*)(double, double)) func)(args[0], args[1]);
case 3:
return ((double (*)(double, double, double)) func)(args[0], args[1], args[2]);
default:
printf("Error: wrapper called with %d arguments\n", n)
break;
}
return 0.0;
}
Written late last night — but my Internet connection went down as I tried to post it. I see Joachim has written essentially the same answer.
Within limits, this will work:
#include <assert.h>
extern double function_invoker(void *func, int n, double *values);
double function_invoker(void *func, int n, double *values)
{
switch (n)
{
case 0:
return (*(double (*)(void))func)();
case 1:
return (*(double (*)(double))func)(values[0]);
case 2:
return (*(double (*)(double, double))func)(values[0], values[1]);
case 3:
return (*(double (*)(double, double, double))func)(values[0], values[1], values[2]);
default:
assert("Need more entries in the switch in function_invoker()" == 0);
return(0.0);
}
}
The obvious limits are how many entries you want to make in the switch. I've seen loosely analogous code go up to over 100 arguments; I'm not sure why that was considered necessary.
That code compiles without warnings under GCC 4.6.0 on Mac OS X 10.8.2:
$ gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -c x.c
$
But if you go with double (*)() in place of void *, you get:
$ gcc -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition -c x.c
x.c:3:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
x.c:5:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
$
Related
I am creating a light test framework. For my local debugging in linux with gcc and clang, I do not get any complaints for mocking a function that has arguments, but mocking it with no arguments. eg.
add.c
int add(int a, int b) {
return a + b;
}
foo.c
#include "add.h"
int add_2(int a) {
return add(a, 2);
}
Now, in order to mock add. I simply created these macros.
testframework.h
#define DECLARE_MOCK(type, name) \
type __var_##name[255]; \
size_t __var_##name##_inc = 0; \
size_t __var_##name##_actual = 0; \
type name() { return (type)__var_##name[__var_##name##_inc++]; }
#define MOCK(name, value) __var_##name[__var_##name##_actual++] = value;
This works well on my linux machine. add(x,y) requires two arguments, but gcc or clang doesn't complain that the mock will essentially have no arguments passed to it, and works perfectly as a stand in. it's this line here type name() ...
Here is the usage. Notice I am mocking add.c capability in this test file.
#include "foo.h"
#include "testframework.h"
DECLARE_MOCK(int, add);
int main() {
DESCRIBE("things");
MOCK(add, 2);
SHOULDB("add", {
ASSERT(add(0, 2) == 2);
});
}
The issue comes in on gcc mac, which complains.
[INFO] CMD: gcc -Wall -Werror -std=c11 -O3 -o target/things tests/things.c obj/things/lib.o
tests/things.c:29:57: error: too many arguments in call to 'add' [-Werror]
SHOULDB("add", { ASSERT(add(0, 2) == 2); });
I would like to keep -Wall and -Werror, I was hoping there was an attribute I could add to the macro, which is the opposite of sentinel.
Take a look at the following code:
typedef enum {
A, B, C
} Foo;
int foo(Foo x) {
switch(x) {
case A: return 1;
case B: return 2;
case C: return 3;
}
}
GCC 10.2 outputs
<source>:11:1: warning: control reaches end of non-void function [-Wreturn-type]
11 | }
| ^
This is because I can pass something like 42 to foo, not only A, B, or C. So the question is: how to tell GCC that only A, B, or C can be handled by the switch statement, otherwise the behavior is undefined? Compiler-specific functionality is acceptable.
Let me point some solutions that don't satisfy me. First, I could just insert default: __builtin_unreachable(); but this would penetrate case analysis: imagine that apparently I'm adding the D variant and the compiler would not tell me that D is unhandled.
Second, I could insert if (x > C) { __builtin_unreachable(); } before the switch statement, but this is too impossible because switch(x) is actually generated by a macro which doesn't know about the variants of Foo, it knows nothing but some variable x.
Third, I could insert #pragma GCC diagnostic ignored "-Wreturn-type", but again, switch(x) is generated by a macro and this is why I cannot revert the diagnostics to the previous state by #pragma GCC diagnostic pop.
Fourth, I could use an array instead of switch but the returned expressions are not constant and are provided by a user of the macro generating switch(x).
And the last one: I could write return 42; after the switch statement but again I want to disable the warning automatically inside the macro generating switch(x) because it's used extensively in my codebase.
Godbolt
If you feel like engaging in some light masochism, you could crudely implement exception-like behavior using setjmp and longjmp:
#include <stdlib.h>
#include <setjmp.h>
#include <stdio.h>
typedef enum Foo {
A, B, C
} Foo;
#define ENUM_OUT_OF_RANGE -1
jmp_buf env;
int foo( Foo x )
{
switch ( x )
{
case A: return 1;
case B: return 2;
case C: return 3;
default: longjmp( env, ENUM_OUT_OF_RANGE ); // "throw" ENUM_OUT_OF_RANGE
}
}
int main( void )
{
int ex;
if ( (ex = setjmp( env )) == 0 ) // "try" block
{
Foo arr[] = {A, B, C, 42};
for ( size_t i = 0; i < 4; i++ )
{
printf( "value of %d = %d\n", arr[i], foo( arr[i] ) );
}
}
else // "catch" block
{
if ( ex == ENUM_OUT_OF_RANGE )
{
fprintf( stderr, "foo was called with a value outside the range of Foo\n" );
}
}
return 0;
}
Builds with no warnings as follows (at least on my system):
gcc -o exceptions -std=c11 -pedantic -Wall -Werror exceptions.c
Output:
$ ./exceptions
value of 0 = 1
value of 1 = 2
value of 2 = 3
foo was called with a value outside the range of Foo
All the functions used in the main file are correctly defined. However when I try to enter the debugging mode, for some reason IDE isn't stepping into said functions when asked to. Instead it acts like a step over and ignores the lines until the very last line, where out of the blue all variables appear in the window ; prior to that, no variable is present whatsoever.
Here's the main file :
#include "pointers.h"
int main(void){
whatisapointer();
whatisthesizeofapointer();
whatareNpointersplacedsuccessively(6);
return 0;
}
the pointers.c file used to define the functions in main :
#include "pointers.h"
void whatisapointer(){
int *pointer;
pointer = allocateOneInteger();
*pointer = 42;
}
void whatisthesizeofapointer(){
int a = sizeof(char);
int b = sizeof(int);
int c = sizeof(char*);
int d = sizeof(int*);
}
void whatareNpointersplacedsuccessively(int N){
int i, *Npointer, *current;
char *Npointerchar, *currentchar;
Npointer = allocateNInteger(N);
current = Npointer;
current = Npointer+1;
current = Npointer+2;
for(i=0;i<N;i++) *(Npointer+i) = i;
N=2*N;
Npointerchar = allocateNChar(N);
currentchar = Npointerchar;
currentchar = Npointerchar+1;
currentchar = Npointerchar+2;
for(i=0;i<N;i++) Npointerchar[i] = 65+i;
Npointer[N-3] = 0x68676665;
current = Npointer+N-3;
}
int* allocateOneInteger(){
return (int*)malloc(1*sizeof(int));
}
int* allocateNInteger(int N){
return (int*)malloc(N*sizeof(int));
}
char* allocateNChar(int N){
return (char*)malloc(N*sizeof(char));
}
void echange(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
void echangep(int *pa,int *pb)
{
int temp;
temp=*pa;
*pa=*pb;
*pb=temp;
}
/* Fonction allocateNFloat
*/
void allocateNFloat(int N){
}
And the makefile :
CC := gcc
FLAGS := -g -Wall -Werror
all : prog
prog : pointers.o mainpointers.o
$(CC) pointers.o mainpointers.o -o prog
fonctions.o : pointers.c pointers.h
$(CC) -c pointers.c $(FLAGS) -o pointers.o
mainpointers.o : mainpointers.c pointers.h
$(CC) -c mainpointers.c $(FLAGS) -o mainpointers.o
clean :
rm -f *.o
rm -f prog
I've done some research, none of which has helped me solve this issue.
You're very likely finding that the compiler is optimizing away your code, because the functions have no side-effects. (If you're not familiar with the concept of side effects, the gist is 'changes to program state that might influence other parts of the program'---compilers aggressively prune away side-effect-free code because, by definition, doing so doesn't change the behavior of the program.)
Even allocating memory isn't a side affect, because correct code should never be able to tell whether another part of the program has allocated memory.
The easiest side-effect is to print out the result of any intermediate computation you want to inspect via the debugger; that will force the optimizer to leave the code in place.
E.g.,
int foo() //no side effects, will be optimized to an empty function or pruned.
{
char *test = malloc(4096);
strcpy(test, "My test string");
return 0;
}
int foo() //dumb side effects
{
char *test = malloc(4096);
strcpy(test, "My test string");
printf("%02x", ((int)test & 0xff) ^ (test[0]) );//make output depend on the operations you wish to observe
return 0;
}
An alternate means to verify that the compiler is pruning away your code would be to disassemble the resulting object file...you should see that the functions consist of a single 'return' instruction...which is what the debugger is showing by highlighting the closing curly brace.
I'm having trouble while writing my garbage collector in C. I give you a minimal and verifiable example for it.
The first file is in charge of dealing with the virtual machine
#include <stdlib.h>
#include <stdint.h>
typedef int32_t value_t;
typedef enum {
Lb, Lb1, Lb2, Lb3, Lb4, Lb5,
Ib, Ob
} reg_bank_t;
static value_t* memory_start;
static value_t* R[8];
value_t* engine_get_Lb(void) { return R[Lb]; }
value_t engine_run() {
memory_start = memory_get_start();
for (reg_bank_t pseudo_bank = Lb; pseudo_bank <= Lb5; ++pseudo_bank)
R[pseudo_bank] = memory_start + (pseudo_bank - Lb) * 32;
value_t* block = memory_allocate();
}
Then I have the actual garbage collector, the minimized code is:
#include <stdlib.h>
#include <stdint.h>
typedef int32_t value_t;
static value_t* memory_start = NULL;
void memory_setup(size_t total_byte_size) {
memory_start = calloc(total_byte_size, 1);
}
void* memory_get_start() { return memory_start; }
void mark(value_t* base){
value_t vbase = 0;
}
value_t* memory_allocate() {
mark(engine_get_Lb());
return engine_get_Lb();
}
Finally, minimal main is:
int main(int argc, char* argv[]) {
memory_setup(1000000);
engine_run();
return 0;
}
The problem I'm getting with gdb is that if I print engine_get_Lb() I get the address (value_t *) 0x7ffff490a800 while when printing base inside of the function mark I get the address (value_t *) 0xfffffffff490a800.
Any idea why this is happening?
Complementary files that may help
The makefile
SHELL=/bin/bash
SRCS=src/engine.c \
src/main.c \
src/memory_mark_n_sweep.c
CFLAGS_COMMON=-std=c11 -fwrapv
CLANG_SAN_FLAGS=-fsanitize=address
# Clang warning flags
CLANG_WARNING_FLAGS=-Weverything \
-Wno-format-nonliteral \
-Wno-c++98-compat \
-Wno-gnu-label-as-value
# Flags for debugging:
CFLAGS_DEBUG=${CFLAGS_COMMON} -g ${CLANG_SAN_FLAGS} ${CLANG_WARNING_FLAGS}
# Flags for maximum performance:
CFLAGS_RELEASE=${CFLAGS_COMMON} -O3 -DNDEBUG
CFLAGS=${CFLAGS_DEBUG}
all: vm
vm: ${SRCS}
mkdir -p bin
clang ${CFLAGS} ${LDFLAGS} ${SRCS} -o bin/vm
File with instructions .asm
5c190000 RALO(Lb,25)
value_t* memory_allocate() {
mark(engine_get_Lb());
return engine_get_Lb();
}
engine_get_Lb is not declared before use. It is assumed by the compiler to return int, per an antiquated and dangerous rule of the C language. It was deprecated in the C standard for quite some time, and now is finally removed.
Create a header file with declarations of all your global functions, and #include it in all your source files.
Your compiler should have at least warned you about this error at its default settings. If it did, you should have read and completely understood the warnings before continuing. If it didn't, consider an upgrade. If you cannot upgrade, permanently add -Wall -Wextra -Werror to your compilation flags. Consider also -Wpedantic and -std=c11.
Hi i was studying C for the first time using C primer plus book then in chapter 16 about _Generic from C11 standard i wrote a program in Eclipse c/c++ and build and it produces 8 errors and warning and i don't know why here is the program and the errors
#include <stdio.h>
#include <math.h>
#define RAD_TO_DEG (180/(4 * atanl(1)))
// generic square root function
#define SQRT(X) _Generic((X),\
long double: sqrtl, \
default: sqrt, \
float: sqrtf)(X)
// generic sine function, angle in degrees
#define SIN(X) _Generic((X),\
long double: sinl((X)/RAD_TO_DEG),\
default: sin((X)/RAD_TO_DEG),\
float: sinf((X)/RAD_TO_DEG)\
)
int main(void)
{
float x = 45.0f;
double xx = 45.0;
long double xxx =45.0L;
long double y = SQRT(x);
long double yy= SQRT(xx);
long double yyy = SQRT(xxx);
printf("%.17Lf\n", y); // matches float
printf("%.17Lf\n", yy); // matches default
printf("%.17Lf\n", yyy); // matches long double
int i = 45;
yy = SQRT(i); // matches default
printf("%.17Lf\n", yy);
yyy= SIN(xxx); // matches long double
printf("%.17Lf\n", yyy);
return 0;
}
errors
make all
Building file: ../generic.c
Invoking: GCC C Compiler
gcc -std=c11 -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"generic.d" -MT"generic.d" -o "generic.o" "../generic.c"
../generic.c: In function ‘main’:
../generic.c:24:5: warning: implicit declaration of function ‘_Generic’ [-Wimplicit-function-declaration]
long double y = SQRT(x);
^
../generic.c:7:5: error: expected expression before ‘long’
long double: sqrtl, \
^
../generic.c:24:21: note: in expansion of macro ‘SQRT’
long double y = SQRT(x);
^
../generic.c:7:5: error: expected expression before ‘long’
long double: sqrtl, \
^
../generic.c:25:21: note: in expansion of macro ‘SQRT’
long double yy= SQRT(xx);
^
../generic.c:7:5: error: expected expression before ‘long’
long double: sqrtl, \
^
../generic.c:26:23: note: in expansion of macro ‘SQRT’
long double yyy = SQRT(xxx);
^
../generic.c:7:5: error: expected expression before ‘long’
long double: sqrtl, \
^
../generic.c:31:10: note: in expansion of macro ‘SQRT’
yy = SQRT(i); // matches default
^
../generic.c:13:1: error: expected expression before ‘long’
long double: sinl((X)/RAD_TO_DEG),\
^
../generic.c:33:10: note: in expansion of macro ‘SIN’
yyy= SIN(xxx); // matches long double
^
make: *** [generic.o] Error 1
14:47:53 Build Finished (took 66ms)
i have used -lm link for math.h and it produces these errors and i don't know why ?
Reason:
_Generic is not supported in gcc until version 4.9, see: https://gcc.gnu.org/wiki/C11Status
Solution:
Try a newer version of gcc.
Example:
In a.c is the code you provided:
[pengyu#GLaDOS tmp]$ gcc a.c -std=c11 -lm -Wall -pedantic
[pengyu#GLaDOS tmp]$ gcc --version | head -n 1
gcc (GCC) 4.9.1 20140903 (prerelease)