I have the following C code:
VALUE find_index(VALUE arr, VALUE num_elements, VALUE element){
....
}
....
VALUE array_distance(VALUE arr1, VALUE arr2){
long arr1_len = RARRAY_LEN(arr1);
VALUE *c_arr2 = RARRAY_PTR(arr2);
long i;
for(i = 0; i < arr2_len; i++){
long arr1_index = find_index(arr1, arr1_len, c_arr2[i]);
....
}
}
When compiling this, I get the following error:
In function ‘VALUE array_distance(VALUE, VALUE, VALUE)’:
error: too few arguments to function ‘VALUE find_index(VALUE, VALUE, VALUE, VALUE)’
Can someone help with what is wrong here?
If you want to use your C functions in other C code inside, you need to use builder.c_raw instead of builder.c, because RubyInline actually tries to make your life easier by changing your code so you can write simple functions quickly. This is however misleading and keeps you from calling your C functions from inside other C functions, because the method signature is altered. This should get you started:
class Test
inline :C do |builder|
builder.c_raw <<-'EOC', :arity => 3
static VALUE
find_index(int argc, VALUE *argv, VALUE self) {
VALUE arr = argv[0];
VALUE num_elements = argv[1];
VALUE element = argv[2];
// actual code...
}
EOC
builder.c_raw <<-'EOC', :arity => 2
static VALUE
array_distance(int argc, VALUE *argv, VALUE self) {
long arr1_len = RARRAY_LEN(argv[0]);
VALUE *c_arr2 = RARRAY_PTR(argv[1]);
long i;
for(i = 0; i < arr2_len; i++){
VALUE[] find_index_argv = {arr1, arr1_len, c_arr2[i]};
long arr1_index = find_index(argc, find_indev_argv, self);
// more code...
}
// must have a return value!
return Qnil;
}
EOC
end
end
Related
I have a function which returns some value and some parameters:
uint8 myFunction(uint8* param1);
uint8 myFunction(uint8* param1)
{
*param1 = 3;
return 1;
}
Later in my code I would like to use the function once with returning a value like:
uint8 a;
uint8 b;
a = myFunction(b);
...
...
and once with just ignoring the parameter, like:
a = myFunction(void);
How to do this in C?
I'd recommend adding a NULL check before dereferencing param1 - that would be wise anyway. Then you can just pass NULL where you want to ignore it.
uint8 myFunction(uint8* param1)
{
if (param1 != NULL)
{
*param1 = 3;
}
return 1;
}
calling code can then just pass NULL:
a = myFunction(NULL);
Of course, it would be good to clearly document this behavior.
I want to pass a 2D array to a function, and the value of the array will not be modified in that function. So I am thinking about doing this way:
#include <Windows.h>
static INT8 TwoDimArrayConst(const INT8 ai_Array[2][2]);
int main(void)
{
INT8 ai_Array[2][2] = { { { 1 }, { 2 } }, { { 3 }, { 4 } } };
(void)TwoDimArrayConst(ai_Array); // Message 0432: [C] Function argument is not of compatible pointer type.
return 1;
}
static INT8 TwoDimArrayConst(const INT8 ai_Array[2][2])
{
INT8 test = 0;
for (INT8 i = 0; i < 2; i++)
{
for (INT8 k = 0; k < 2; k++)
{
if (ai_Array[i][k] > 0)
{
test = 1;
}
}
}
if (test == 0)
{
test = 2;
}
return test;
}
However, it gave me the QAC error when I enabled depth 5 QAC setting as the one I put is the code comment above:
// Message 0432: [C] Function argument is not of compatible pointer type.
If I remove the const in the function declaration and definition, so the function is like:
static INT8 TwoDimArrayConst(INT8 ai_Array[2][2]);
this error will be gone, but there will be another error saying:
> The object addressed by the pointer parameter 'ai_Array' is not
> modified and so the pointer could be of type 'pointer to const'.
So how to resolve this dilemma? I cannot define ai_Array to be const array in the main fuction since some other function may still want to modify the value.
Also, I am looking for the solution that still maintain the double brackets(no need to pass row size and column size as separate arguments) in the function, instead of treat it as a 1D array.
the following proposed code:
uses the C library functions rather than the windows functions, since I'm running on linux, not windows
performs the desired functionality
cleanly compiles
takes advantage of arrays, in C, being laid out consecutively in memory
takes advantage of "accessing an array name degrades to the address of the first byte of the array"
removes all the unneeded braces (which are doing nothing but cluttering the code)
documents why each header file is included
passes the size of the array as an parameter to the called function (should always either do this or include some kind of 'marker' in the contents of the array)
all the above allows treating the array as a 1 dimensional array
breaks out of the loop in the called function as soon as the terminating condition is encountered
BTW: the header file: windows.h is not portable
and now, the proposed code:
//#include <Windows.h>
#include <stdio.h> // printf()
#include <stdint.h> // int8_t
static int8_t TwoDimArrayConst( const int8_t *ai_Array, size_t size );
int main(void)
{
const int8_t ai_Array[2][2] = { { 1, 2 }, { 3, 4 } };
int8_t returnValue = TwoDimArrayConst(( int8_t* const )ai_Array, sizeof( ai_Array) / sizeof( int8_t ));
printf( "%d\n", returnValue );
return 1;
}
static int8_t TwoDimArrayConst( const int8_t *ai_Array, size_t size )
{
int8_t test = 2;
for ( size_t i = 0; i < size; i++)
{
if (ai_Array[i] > 0)
{
test = 1;
break;
}
}
return test;
}
A run of the proposed code results in:
1
I have written a type:
typedef struct
{
int Tape[TAPE_SIZE];
int *Head;
int Tape_Count;
int Loop_Start_Count;
} Tarpit;
I try to initialize this type with the following function:
void Tarpit_Initialize(Tarpit Tarpit)
{
Tarpit.Tape_Count = 0;
Tarpit.Loop_Start_Count = 0;
int Index;
for(Index = 0; Index < TAPE_SIZE; Index++)
{
Tarpit.Tape[Index] = INITIAL_SIZE;
}
}
However, it does not seem to work. If I run this:
Tarpit Foo;
Tarpit_Initialize(Foo);
printf("Tarpit Initialization Test: \n");
int index;
for(index = 0; index < TAPE_SIZE ; index++)
{
if(Foo.Tape[index] == INITIAL_SIZE)
{
printf("%d: %d \n", index, Foo.Tape[index]);
}
else
{
printf("%d: %d !ERROR \n", index, Foo.Tape[index]);
}
}
I get several non-zero values (I have set #define TAPE_SIZE 10000 and #define INITIAL_SIZE 0)
Moreover, if I run the test without running Tarpit_Initialize(Foo), I get exactly the same results. The initializer does not seem to work. Why/how could I implement it in an other way? I would like to set every element of Foo.Tape to zero.
Problem solved!
You are passing Tarpit by value:
void Tape_Initialize(Tarpit Tarpit)
That means it is only a copy of Tarpit. You have to pass a pointer to it to be able to modify it.
void Tape_Initialize(Tarpit* Tarpit)
and pass it as pointer (note the name of the function called!):
Tape_Initialize(&Foo);
and the use the -> operator to modify it. For instance:
Tarpit->Tape_Count = 0;
Moreover, as "Elias Van Ootegem" pointed out, you should not use sizeof(Tarpit.Tape) to get the size of the array but TAPE_LENGTH that you defined. Because sizeof() will give you a size in bytes not in elements.
Have you checked the function u are calling ??
Its "Tarpit_Initialize(Foo);"
But the Function u are using it to initialize "void Tape_Initialize(Tarpit Tarpit)".
I think even what u have implemented should work fine .
I register functions at a global registry. A function can have multiple arguments. I can register and call them from the registry.
Here is one of my unit tests to understand the registry.
void *a_test_function_d(int a, char *b){
printf("*** c_test called\n");
isRunD = a;
testChar = b;
return NULL;
}
TEST(testWithMultibleArguments) {
isRunD = 0;
testChar = "";
add_command(a_test_function_d);
assertEquals(1, avl_tree_count(command_registry));
exec_command("a_test_function_d", 42, "test");
assertEquals(42, isRunD);
assertEquals("test", testChar);
avl_tree_free(command_registry);
command_registry = NULL;
}
This works fine for me so far. But here comes the part I can’t find a nice solution for. From a line-parser i get tokens. The first one should be the command, the following tokens are the arguments. If i would have a fixed length of arguments, than i doesn’t have any problems, but how can I construct a function or a macro that handles a variable count of tokens to pass them as arguments to a function?
This is what i have so far:
// split lines into tokens
char *token;
token = strtok(linebuffer," ");
if (token) {
if ( has_cammand(token) ) {
// HOW TO PUT ARGS from strtok(linebuffer," ") to FUNCTION....
exec_command(token /* , a1, a2, a3 */ );
} else {
uart_puts("Command not found.\n");
}
}
My line buffer is a char* and can look like:
find honigkuchen
set name peter
(coming from a user input interactive shell).
the prototypes of the functions would be:
void *find(char *);
void *set(char *, char *);
Of cause I can define a macro and count _VA_ARGS_, or the array and do a if-else on 1, 2, 3, 4, … Parameters, but this seems a bit messy to me.
There must be a better way to convert a array, to a parameter list.
Pass the array and the number of items in the array as arguments to the function under test. Is there some reason to complicate this further?
Keep in mind that an array passed to a function is really a pointer to the first item in the array.
So, if you have:
// Prototype for test function:
bool testFunction( char *items, int itemCount );
char items[10];
int itemCount = 0;
// Get items from where ever
items[0] = 'a';
items[1] = 'r';
items[2] = 'r';
items[3] = 'a';
items[4] = 'y';
itemCount = 5;
// Assume testFunction returns true if the test succeeds, else false
if( testFunction( items /*or &items[0] to make it more clear*/, itemCount ) )
puts( "Success!" );
else
puts( "Failure :(" );
Ask away if anything is unclear...
Guys so I'm working on the web service assignment and I have the server dishing out random stuff and reading the uri but now i want to have the server run a different function depending on what it reads in the uri. I understand that we can do this with function pointers but i'm not exactly sure how to read char* and assign it to a function pointer and have it invoke that function.
Example of what I'm trying to do: http://pastebin.com/FadCVH0h
I could use a switch statement i believe but wondering if there's a better way.
For such a thing, you will need a table that maps char * strings to function pointers. The program segfaults when you assign a function pointer to string because technically, a function pointer is not a string.
Note: the following program is for demonstration purpose only. No bounds checking is involved, and it contains hard-coded values and magic numbers
Now:
void print1()
{
printf("here");
}
void print2()
{
printf("Hello world");
}
struct Table {
char ptr[100];
void (*funcptr)(void)
}table[100] = {
{"here", print1},
{"hw", helloWorld}
};
int main(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < 2; i++){
if(!strcmp(argv[1],table[i].ptr) { table[i].funcptr(); return 0;}
}
return 0;
}
I'm gonna give you a quite simple example, that I think, is useful to understand how good can be functions pointers in C. (If for example you would like to make a shell)
For example if you had a struct like this:
typedef struct s_function_pointer
{
char* cmp_string;
int (*function)(char* line);
} t_function_pointer;
Then, you could set up a t_function_pointer array which you'll browse:
int ls_function(char* line)
{
// do whatever you want with your ls function to parse line
return 0;
}
int echo_function(char* line)
{
// do whatever you want with your echo function to parse line
return 0;
}
void treat_input(t_function_pointer* functions, char* line)
{
int counter;
int builtin_size;
builtin_size = 0;
counter = 0;
while (functions[counter].cmp_string != NULL)
{
builtin_size = strlen(functions[counter].cmp_string);
if (strncmp(functions[counter].cmp_string, line, builtin_size) == 0)
{
if (functions[counter].function(line + builtin_size) < 0)
printf("An error has occured\n");
}
counter = counter + 1;
}
}
int main(void)
{
t_function_pointer functions[] = {{"ls", &ls_function},
{"echo", &echo_function},
{NULL, NULL}};
// Of course i'm not gonna do the input treatment part, but just guess it was here, and you'd call treat_input with each line you receive.
treat_input(functions, "ls -laR");
treat_input(functions, "echo helloworld");
return 0;
}
Hope this helps !