I am having a hard time compiling this C code.
Basically what happens is:
it does compile but when I run it (on Terminal) it prints me:Illegal instruction
I tried to debug it and on Xcode and when it attempts to execute (*fraction).print() it says: EXC_BAD_ACCESS
if I delete the (*fraction).print() line everything works fine (same happens if I only delete the next line)
GNU99 and -fnested-functions flag is enabled
I do not want to change the main function just the other stuff
This code drove me crazy for a whole afternoon so a little help would be really appreciated.
Thankyou
#include <stdlib.h>
#include "string.h"
#include "stdio.h"
typedef struct
{
int numerator;
int denominator;
void (*print)(); // prints on screen "numerator/denominator"
float (*convertToNum)(); //returns value of numerator/denominator
void (*setNumerator)(int n);
void (*setDenominator)(int d);
} Fraction;
Fraction* allocFraction(Fraction* fraction); //creates an uninitialized fraction
void deleteFraction(Fraction *fraction);
Fraction* allocFraction(Fraction* fraction)
{
void print()
{
int a= 10;
printf("%i/%i", (*fraction).numerator, (*fraction).denominator);
a--;
}
float convertToNum()
{
return (float)(*fraction).numerator/(float)(*fraction).denominator;
}
void setNumerator (int n)
{
(*fraction).numerator= n;
}
void setDenominator (int d)
{
(*fraction).denominator= d;
}
if(fraction== NULL)
fraction= (Fraction*) malloc(sizeof(Fraction));
if(fraction)
{
(*fraction).convertToNum= convertToNum;
(*fraction).print= print;
(*fraction).setNumerator= setNumerator;
(*fraction).setDenominator= setDenominator;
}
return fraction;
}
void deleteFraction(Fraction *fraction)
{
free(fraction);
}
int main (int argc, const char * argv[])
{
Fraction *fraction= allocFraction(fraction);
(*fraction).setNumerator(4);
(*fraction).setDenominator(7);
(*fraction).print(); //EXC_BAD_ACCESS on debug. Illegal instruction in Terminal
printf("%f", (*fraction).convertToNum());
(*fraction).print();
deleteFraction(fraction);
return 0;
}
You can't write C in the same way you write Javascript.
Specifically, it appears that print() is a nested function inside allocFraction() (which is itself not standard C but a gcc extension). You can't call a nested function through a function pointer from outside the scope of where it's defined. This is true even if you don't access anything in the outer scope from the nested scope.
Your code appears to be attempting to do object-oriented programming in C. Have you considered C++?
Related
I am trying to add items to a map that is a private variable in a class based on if certain parameters are met. When I try to use the insert function for std::map or the [] operator, nothing happens. I don't even get an error. During debugging the code executes like everything is fine but the map stays empty.
I have tried multiple ways to insert to the map including the [] operator and different insert arguments.
class foo {
private:
std::map<std::string, int> map;
public:
void bar();
};
In cpp file:
void foo::bar() {
if(condition)
map.insert(std::make_pair("string", 1));
}
There are no error messages or warnings in the compiler or during debugging.
If the basic STD map usage works, maybe the problem sits in your condition implementation
#include <iostream>
#include <map>
class Foo {
std::map<std::string, int> map;
public:
void bar();
void print();
};
void Foo::bar() {
// if (condition) // weird condition causing failure
map.insert(std::make_pair("string", 1));
}
void Foo::print() {
std::cout << map.size() << std::endl;
std::cout << map.at("string") << std::endl;
}
int main(void) {
Foo foo;
foo.bar();
foo.print();
}
In CUDA 9.2 I have something like this:
#ifdef __CUDA_ARCH__
struct Context { float n[4]; } context;
#else
typedef __m128 Context;
#endif
struct A { float k[2]; };
struct B { float q[4]; };
struct FTransform : thrust::unary_function<A, B>
{
const Context context;
FTransform(Context context) : context(context){}
__device__ __host__ B operator()(const A& a) const
{
B b{{a.k[0], a.k[1], a.k[0]*context.n[0], a.k[1]*context.n[1]}};
return b;
}
};
void DoThrust(B* _bs, const Context& context, A* _as, uint32_t count)
{
thrust::device_ptr<B> bs = thrust::device_pointer_cast(_bs);
thrust::device_ptr<A> as = thrust::device_pointer_cast(_as);
FTransform fTransform(context);
auto first = thrust::make_transform_iterator(as, fTransform);
auto last = thrust::make_transform_iterator(as + count, fTransform);
thrust::copy(first, last, bs);
}
int main(int c, char **argv)
{
const uint32_t Count = 4;
Context context;
A* as;
B* bs;
cudaMalloc(&as, Count*sizeof(A));
cudaMalloc(&bs, Count*sizeof(B));
A hostAs[Count];
cudaMemcpy(as, hostAs, Count * sizeof(A), cudaMemcpyHostToDevice);
DoThrust(bs, context, as, Count);
B hostBs[Count];
cudaMemcpy(hostBs, bs, Count * sizeof(B), cudaMemcpyDeviceToHost);//crash
return 0;
}
Then when I call a standard cudaMemcpy() call later on the results I get the exception "an illegal memory access was encountered".
If I replace the thrust code with a non-thrust equivalent there is no error and everything works fine. Various combinations of trying to copy to device_vectors etc I get different crashes that seem to be thrust trying to release the device_ptr's for some reason - so maybe it is here for some reason?
== UPDATE ==
Ok that was confusing it appears it's due to the functor FTransform context member variable in my actual more complicated case. This specifically:
struct FTransform : thrust::unary_function<A, B>
{
#ifdef __CUDA_ARCH__
struct Context { float v[4]; } context;
#else
__m128 context;
#endif
...
};
So I guess it's an alignment problem somehow => in fact it is, as this works:
#ifdef __CUDA_ARCH__
struct __align__(16) Context { float v[4]; } context;
#else
__m128 context;
#endif
The solution is to ensure that if you use aligned types in thrust functor members (such as __m128 SSE types) that are copied to the GPU, that they are defined as aligned both during NVCC's CPU and GPU code build passes - and not accidentally assume even if a type may seem to naturally align to it's equivalent in the other pass that it will be ok, as otherwise bad hard to understand things may happen.
So for example the _ align _(16) is necessary in code like this:
struct FTransform : thrust::unary_function<A, B>
{
#ifdef __CUDA_ARCH__
struct __align__(16) Context { float v[4]; } context;
#else
__m128 context;
#endif
FTransform(Context context) : context(context){}
__device__ __host__ B operator()(const A& a) const; // function makes use of context
};
In trying to shorted my code for readability, I wound up changing too much and making mistakes. This is still condensed but taken straight from my code.
My problem is that I have a class called "function" and a derived class "pwfunction" which both have the virtual () operator. I'd like to pass an array of pointers to my "function" objects to various actual functions and use the () operator.
Final edit: This is a SSCCE version of what I'm talking about.
#include <iostream>
using namespace std;
class function
{
public:
virtual double operator () (double x) {return 1.5;}
};
class pwfunction : public function
{
public:
virtual double operator() (double x) {return 2.0;}
};
void interface();
void definefuncs (function** funcs, long unsigned numfuncs);
void interpolate(function* infunc);
void solvefuncs(function** funcs, long unsigned numfuncs);
int main()
{
interface();
return 0;
}
void interface()
{
long unsigned numfuncs = 1;
function* funcs[numfuncs];
definefuncs(funcs, numfuncs);
solvefuncs(funcs, numfuncs);
}
void definefuncs (function** funcs, long unsigned numfuncs)
{
interpolate(funcs[0]);
}
void interpolate(function* infunc)
{
infunc = new pwfunction();
cout<< (*infunc)(1.5)<<endl; //works
}
void solvefuncs(function** funcs, long unsigned numfuncs)
{
cout<< (*funcs[0])(1.5); //Error Message: Segmentation fault
}
The problem comes from the following:
void interpolate(function* infunc)
{
infunc = new pwfunction();
cout<< (*infunc)(1.5)<<endl; //works
}
is probably not doing what you want. infunc is allocated locally, and this does not affect anything else outside or this function (and is btw a memory leak). Interpolate should either return infunc, or allocate the original variable, such as
void interpolate(function*& infunc) ...
You don't allocate array for the funclist data in somefunction, so anything can happen. Perhaps you mean
func* funclist[1];
to indicate a one-element array of func pointers.
I was trying to make somtehing like this (actually I need to write some integration functions) in CUDA
#include <iostream>
using namespace std;
float f1(float x) {
return x * x;
}
float f2(float x) {
return x;
}
void tabulate(float p_f(float)) {
for (int i = 0; i != 10; ++i) {
std::cout << p_f(i) << ' ';
}
std::cout << std::endl;
}
int main() {
tabulate(f1);
tabulate(f2);
return 0;
}
output:
0 1 4 9 16 25 36 49 64 81
0 1 2 3 4 5 6 7 8 9
I tried the following but only got the error
Error: Function pointers and function template parameters are not supported in sm_1x.
float f1(float x) {
return x;
}
__global__ void tabulate(float lower, float upper, float p_function(float), float* result) {
for (lower; lower < upper; lower++) {
*result = *result + p_function(lower);
}
}
int main() {
float res;
float* dev_res;
cudaMalloc( (void**)&dev_res, sizeof(float) ) ;
tabulate<<<1,1>>>(0.0, 5.0, f1, dev_res);
cudaMemcpy(&res, dev_res, sizeof(float), cudaMemcpyDeviceToHost);
printf("%f\n", res);
/************************************************************************/
scanf("%s");
return 0;
}
To get rid of your compile error, you'll have to use -gencode arch=compute_20,code=sm_20 as a compiler argument when compiling your code. But then you'll likely have some runtime problems:
Taken from the CUDA Programming Guide http://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#functions
Function pointers to __global__ functions are supported in host code, but not in device code.
Function pointers to __device__ functions are only supported in device code compiled for devices of compute capability 2.x and higher.
It is not allowed to take the address of a __device__ function in host code.
so you can have something like this (adapted from the "FunctionPointers" sample):
//your function pointer type - returns unsigned char, takes parameters of type unsigned char and float
typedef unsigned char(*pointFunction_t)(unsigned char, float);
//some device function to be pointed to
__device__ unsigned char
Threshold(unsigned char in, float thresh)
{
...
}
//pComputeThreshold is a device-side function pointer to your __device__ function
__device__ pointFunction_t pComputeThreshold = Threshold;
//the host-side function pointer to your __device__ function
pointFunction_t h_pointFunction;
//in host code: copy the function pointers to their host equivalent
cudaMemcpyFromSymbol(&h_pointFunction, pComputeThreshold, sizeof(pointFunction_t))
You can then pass the h_pointFunction as a parameter to your kernel, which can use it to call your __device__ function.
//your kernel taking your __device__ function pointer as a parameter
__global__ void kernel(pointFunction_t pPointOperation)
{
unsigned char tmp;
...
tmp = (*pPointOperation)(tmp, 150.0)
...
}
//invoke the kernel in host code, passing in your host-side __device__ function pointer
kernel<<<...>>>(h_pointFunction);
Hopefully that made some sense. In all, it looks like you would have to change your f1 function to be a __device__ function and follow a similar procedure (the typedefs aren't necessary, but they do make the code nicer) to get it as a valid function pointer on the host-side to pass to your kernel. I'd also advise giving the FunctionPointers CUDA sample a look over
Even though you may be able to compile this code (see #Robert Crovella's answer) this code will not work. You cannot pass function pointers from host code as the host compiler has no way of figuring out the function address.
Here is a simple class for function pointers that are callable from within a kernel I wrote based on this question:
template <typename T>
struct cudaCallableFunctionPointer
{
public:
cudaCallableFunctionPointer(T* f_)
{
T* host_ptr = (T*)malloc(sizeof(T));
cudaMalloc((void**)&ptr, sizeof(T));
cudaMemcpyFromSymbol(host_ptr, *f_, sizeof(T));
cudaMemcpy(ptr, host_ptr, sizeof(T), cudaMemcpyHostToDevice);
cudaFree(host_ptr)
}
~cudaCallableFunctionPointer()
{
cudaFree(ptr);
}
T* ptr;
};
you could use it like this:
__device__ double func1(double x)
{
return x + 1.0f;
}
typedef double (*func)(double x);
__device__ func f_ = func1;
__global__ void test_kernel(func* f)
{
double x = (*f)(2.0);
printf("%g\n", x);
}
int main()
{
cudaCallableFunctionPointer<func> f(&f_);
test_kernel << < 1, 1 >> > (f.ptr);
}
output:
3
#include <stdio.h>
#include <string.h>
void func1 (void) { printf( "1\n" ); }
void func0 (void) { printf( "0\n" ); }
typedef struct {
void (*func0)(void);
void (*func1)(void);
}mainJT;
static const mainJT coreJT = {
core_func0,
core_func1
};
mainJT currJT;
int main()
{
currJT=coreJT;
coreJT.core_func0();
getchar();
return 0;
}
Please help me fix the errors, I am sure I am making some obvious mistakes. Thanks.
Your question isn't quite clear but I see what I can find.
typedef struct {
void (*func0)(void);
void (*func1)(void);
} mainJT;
Here you are declaring a struct with function pointer members func0 and func1. Then you are trying to define a coreJT variable via an initializer list:
static const mainJT coreJT = {
core_func0,
core_func1
};
But this doesn't work, because there are no functions called core_func0 or core_func1!
Also you try to call
coreJT.core_func0();
which is also incorrect since your struct doesn't have a member of name core_func0.
For a possible solution try renaming your functions like so:
void core_func1 (void) { printf( "1\n" ); }
void core_func0 (void) { printf( "0\n" ); }
and call your function pointer by
coreJT.func0();
i see lot of errors:
for eg: the correct way of initializing a structure is :
/* Define a type point to be a struct with integer members x, y */
typedef struct {
int x;
int y;
} point;
/* Define a variable p of type point, and initialize all its members inline! */
point p = {1,2};
so your part of the code is :
mainJT coreJT = {
core_func0;
core_func1;
};
completely wrong.
also where are the functions core_func1 core_func0 are declared and defined .i cannot see them.
i guess you first need to go through structures in c