casting to const void* arguments on typdef function to use qsort in C - function

I have made the following typedefs in my program (C):
typedef void* ListElement;
typedef int(*CompareListElements)(ListElement, ListElement);
i have made a function pointer in my code:
CompareListElements compareElement
Later in the code i wish to use qsort on an array of ListElements:
qsort(elementsArray,listGetSize(list),sizeof(list->dummyHead->next->element, compareElement);
However the compiler states: "passing argument 4 of 'qsort' from incompatible pointer type".
I fear that it is because the qsort requires a function in the format of int (const void*, const void*). when i supply int (void*, void*).
Is there a way of casting the arguments of compareElement to (const void*, const void*), while calling qsort or before, WITHOUT changing the typedef?
Thanks

Simply cast the pointer to the appropriate type.
typedef int(*ConstCompareListElements)(const void *, const void *);
qsort(elementsArray,listGetSize(list),sizeof(list->dummyHead->next->element,
(ConstCompareListElements)compareElement);

Related

const function doesn't return char*

Can anyone explain me why if I make the function get_fName a const function, it returns _fName only with the casting (char*)? Without casting, it not compiles.
On the other hand, if I remove the const, it returns _fName also without casting?
class Student
{
int _id;
char _fName [20];
char* get_fName() const;
}
// implementation
char* Student::get_fName () const
{
return (char*)_fName;
}
What you're experiencing is the expected behaviour. When you declare a function const, you're effectively saying "this function will not modify the class' member variables". Thus, all the member variables to such a function appear as const. GCC emphasizes this in the error message :
x.cpp: In member function ‘char* Student::get_fName() const’:
x.cpp:11:12: error: invalid conversion from ‘const char*’ to ‘char*’ [-fpermissive]
return _fName;
^
This is because, to a const function, _fName appears to be a const char[20]. Conversion to a char[20], which would be modifiable, is not allowed unless you use a C-style cast or const_cast. When you don't declare the function const, _fName appears to be a char[20], which is implicitly convertible to char*, and the function works without casting.
However, this should not be done : if you need a function to modify the object's internals, simply don't declare it const, as it violates the contract you state that the function is making.
On another note, consider using std::string for storing strings in your program.

How can I use templates or typedefs to select between float/double vector types?

A usual way to target different floating point precisions (float / double) is either by typedefs
typedef float Real;
//typedef double Real;
or by using templates
template<typename Real>
...
This is convenient, but anyone has ideas how to use the CUDA types float2/float3/... and make_float2/make_float3/... ? Sure, I could make #defines or typedefs for all of them but that seems not very elegant.
You can implement helper class that will concatenate type and channels number:
template <typename T, int cn> struct MakeVec;
template <> struct MakeVec<float, 3>
{
typedef float3 type;
};
template <> struct MakeVec<double, 3>
{
typedef double3 type;
};
// and so on for all combination of T and cn
Usage:
template <typename T>
void func()
{
typedef typename MakeVec<T, 4>::type vec4_type;
vec4_type vec4; // for T=float it will be float4, for T=double it will be double4
}
You can find implementation here

Writing a simple thrust functor operating on some zipped arrays

I am trying to perform a thrust::reduce_by_key using zip and permutation iterators.
i.e. doing this on a zipped array of several 'virtual' permuted arrays.
I am having trouble in writing the syntax for the functor density_update.
But first the setup of the problem.
Here is my function call:
thrust::reduce_by_key( dflagt,
dflagtend,
thrust::make_zip_iterator(
thrust::make_tuple(
thrust::make_permutation_iterator(dmasst, dmapt),
thrust::make_permutation_iterator(dvelt, dmapt),
thrust::make_permutation_iterator(dmasst, dflagt),
thrust::make_permutation_iterator(dvelt, dflagt)
)
),
thrust::make_discard_iterator(),
danswert,
thrust::equal_to<int>(),
density_update()
)
dmapt, dflagt are of type thrust::device_ptr<int> and dvelt , dmasst and danst are of type
thrust::device_ptr<double>.
(They are thrust wrappers to my raw cuda arrays)
The arrays mapt and flagt are both index vectors from which I need to perform a gather operation from the arrays dmasst and dvelt.
After the reduction step I intend to write my data to the danswert array. Since multiple arrays are being used in the reduction, obviously I am using zip iterators.
My problem lies in writing the functor density_update which is binary operation.
struct density_update
{
typedef thrust::device_ptr<double> ElementIterator;
typedef thrust::device_ptr<int> IndexIterator;
typedef thrust::permutation_iterator<ElementIterator,IndexIterator> PIt;
typedef thrust::tuple< PIt , PIt , PIt, PIt> Tuple;
__host__ __device__
double operator()(const Tuple& x , const Tuple& y)
{
return thrust::get<0>(*x) * (thrust::get<1>(*x) - thrust::get<3>(*x)) + \
thrust::get<0>(*y) * (thrust::get<1>(*y) - thrust::get<3>(*y));
}
};
The value being returned is a double . Why the binary operation looks like the above functor is
not important. I just want to know how I would go about correcting the above syntactically.
As shown above the code is throwing a number of compilation errors. I am not sure where I have gone wrong.
I am using CUDA 4.0 on GTX 570 on Ubuntu 10.10
density_update should not receive tuples of iterators as parameters -- it needs tuples of the iterators' references.
In principle you could write density_update::operator() in terms of the particular reference type of the various iterators, but it's simpler to have the compiler infer the type of the parameters:
struct density_update
{
template<typename Tuple>
__host__ __device__
double operator()(const Tuple& x, const Tuple& y)
{
return thrust::get<0>(x) * (thrust::get<1>(x) - thrust::get<3>(x)) + \
thrust::get<0>(y) * (thrust::get<1>(y) - thrust::get<3>(y));
}
};

Use SWIG to apply multiple Java data types for same C data type

I have two C functions that I'm exposing through SWIG to my Java layer and both have an input param with a const void * data type ("val) that needs to be a uint8_t for the addCategory function but a char for the addAttribute function. I'm currently, in the SWIG Interface file, using the %apply to map the const void * C type to a short on the Java side. Is there a way to modify the SWIG interface file to support both a char (String) and a uint8_t (short) for the const void * input parameter?
C Functions from header file:
int
addCategory(query_t *query, type_t type, const void *val);
int
addAttribute(query_t *query, type_t type, const void *val);
SWIG Interface File:
%module Example
%include "stdint.i"
void setPhy_idx(uint32_t value);
%include "arrays_java.i"
void setId(unsigned char *value);
%{
#include "Example.h"
%}
%apply char * { unsigned char * };
%apply char * { void * };
%apply uint8_t { const void * }
%apply int32_t { int32_t * }
%include "Example.h"
You can't directly do this - what type would be used in this place in Java? You need to help SWIG decide that in some way.
You have (at least) three possible solutions:
Use a type hierarchy - The base type will be what the function takes, the subclasses will get wrapped also. You could do this on the C++ side, or on the Java side using SWIG's typemap facilities. I think this is needlessly complicated though, so I've not made an example here.
Use overloads (or even different functions, with different names altogether - you could use %rename to make them back into overloads in Java even if they have different names in C)
Use a union. This will get wrapped with set and get functions by SWIG:
%module test
union values {
unsigned char *string;
void *generic;
uint8_t someOtherThing;
uint32_t number;
};
void func(values v);
This results in a Java class called values, which func() takes and can pass one of the members of the union through. Clearly you'd want to %apply appropriate typemaps for the members of the union.

Cannot overload make_uint4 function

I'm trying to overload make_uint4 in the following manner:
namespace A {
namespace B {
inline __host__ __device__ uint4 make_uint4(uint2 a, uint2 b) {
return make_uint4(a.x, a.y, b.x, b.y);
}
}
}
But when I try to compile it, nvcc returns an error:
error: no suitable constructor exists to convert from "unsigned int" to "uint2"
error: no suitable constructor exists to convert from "unsigned int" to "uint2"
error: too many arguments in function call
All these errors point to the "return…" line.
I was able to get a partial repro on VS 2010 and CUDA 4.0 (the compiler built the code OK but Intellisense flagged the error you are seeing). Try the following:
#include "vector_functions.h"
inline __host__ __device__ uint4 make_uint4(uint2 a, uint2 b)
{
return ::make_uint4(a.x, a.y, b.x, b.y);
}
This fixed it for me.
I have no problem compiling it in Visual Studio+nvcc. What compiler are you using?
If that would be of any help: make_uint4 is defined in vector_functions.h, line 170 as
static __inline__ __host__ __device__ uint4 make_uint4(unsigned int x, unsigned int y, unsigned int z, unsigned int w)
{
uint4 t; t.x = x; t.y = y; t.z = z; t.w = w; return t;
}
Update:
I get similar error when I try to overload the function while being inside my custom namespace. Are you certain you are not inside one? If so, try putting :: in front of function call to refer to global scope, i.e:
return ::make_uint4(a.x, a.y, b.x, b.y);
I don't have the library code, but it seems like the compiler doesn't like overloaded device functions (as they are treated just like really fancy inline macros). What is does is shadow (hide) the old make_uint4(a,b,c,d) with your new make_uint4(va, vb) and try to call the latter with 4 uint parameters. That doesn't work because there is no conversion from uint to uint2 (as indicated by the first two error messages) and there are 4 instead of 2 arguments (the last error message).
Use a slightly different function name like make_uint4_from_uint2s and you'll be fine.