What is the best way to load from a const pointer using altivec?
According to the documentation (and my results) vec_ld doesn't take a const pointer as an argument:
http://www-01.ibm.com/support/knowledgecenter/SS2LWA_12.1.0/com.ibm.xlcpp121.bg.doc/compiler_ref/vec_ld.html
Hence something like this will fail:
void foo(const float* A){
vector4double a = vec_ld(0,A);
...
}
A nasty work-around would be:
void foo(const float* A){
vector4double a = vec_ld(0,const_cast<float*>A);
...
}
Is there a better way to do this?
Thank you.
Use const_cast.
It exists exactly for that purpose: handling const-incorrect APIs.
Function vec_ld loads a 128-bit vector (4 float values) to Altivec register. Loading is performed from 16-byte aligned address. It doesn't work properly if address doesn't have a 16-byte align. In that case you have to use next function:
typedef __vector uint8_t v128_u8;
typedef __vector float v128_f32;
inline v128_f32 Load(const float * p)
{
v128_u8 lo = vec_ld(0, p);
v128_u8 hi = vec_ld(A, p);
return (v128_f32)vec_perm(lo, hi, vec_lvsl(0, p));
}
or use function vec_vsx_ld if you have Power7 or Power8 CPU.
Your const float * means you point to something that is not modifiable, but you still can point to something else.
I don't know about your function vec_ld but I guess as it demands a pointer to a float, the function will change the value pointed.
Then, you have to provide a modifiable value.
I would not use your nasty workaround, because the user calling your method won't expect it's float value to be modified and it will surely because a nasty bug in the future.
If you could change your method foo to foo(float * A) or foo(float & A) it would be a relief.
For more information about const pointer, see : What is the difference between const int*, const int * const, and int const *?
Related
Suppose, I have a class, like:
struct A
{
uint8_t f1;
int16_t f2;
};
And I need to set it's members values from a memory buffer data, like:
uint8_t * memory=device.getBufferedDataFromDevice();
A a;
a.f1=*((uint8_t*)&memory[someAddress]);
a.f2=*((int16_t*)&memory[someOtherAddress]);
But I'd like to make it more flexible, and avoid the explicit type cast, to have a possibility to change the type in the declaration without changing the rest of the code. Of course, I could achieve it with something like:
memcpy((void*)&a.f1, (void*)&memory[someAddress], sizeof(A::f1));
But I'd also want to avoid calling a function for a simple types like 1-4 bytes long integers (which I have), as the simple assignment could be compiled to a single CPU instruction. Please advise, what is the c++ way to implement this?
Thank you!
memcpy is fully understood by every modern C++ compiler, and there is not going to be an actual function call unless you take its address, store that in a pointer, then confuse the compiler enough that it no longer knows the pointer points at memcpy.
Or, you know, turn off optimizations.
memcpy((void*)&a.f1, (void*)&memory[someAddress], sizeof(A::f1));
there is neither reason to cast to void*, nor use dangerous C-style casts, here.
std::memcpy(&a.f1, &memory[someAddress], sizeof(a.f1));
this is a standards-compliant way to move memory that represents data of the same type as a.f1 over a.f1, assuming a.f1 is trivially copyable. (Note I used the same token sequence -- a.f1 -- for both the written-to stuff and the size.)
The compiler will optimize this into appropriate assembly, and there will be no function-call overhead.
Live example, you can see the generated assembly.
Now, you may object "but there is no guarantee!".
The C++ standard does not include a guarantee that a+b won't be implemented as a loop int r = 0; for (int i = 0; i < a; ++i){++r;} for (int i = 0; i < b; ++i){++r;}.
You cannot presume your C++ compiler is hostile.
Existing C++ compilers optimize calls to memcpy. Writing code assuming it won't happen is a waste of time.
You can also write a slightly safer memcpy
template<class Dest>
void memcpyT( Dest* dest, void const* src ) {
static_assert( std::is_trivially_copyable_v<Dest> );
memcpy( dest, src, sizeof(Dest) );
}
which I included as an alternative in the above live example.
You can have a code similar to this:
template<typename T>
void mymemcopy(T* a, void* b) {
memcpy((void*)a, b, sizeof(T));
}
template<typename T>
constexpr void mymemcopy(T** a, void* b) {
*a = static_cast<T*>(b);
}
constexpr void mymemcopy(int* a, void* b) {
*a = *(int*)b;
}
constexpr void mymemcopy(unsigned char* a, void* b) {
*a = *(unsigned char*)b;
}
int main()
{
int a, b =10;
mymemcopy(&a, &b);
double a1, b1 =10;
mymemcopy(&a1, &b1);
unsigned char a2, b2 =10;
mymemcopy(&a2, &b2);
unsigned char *a3, *b3 =nullptr;
mymemcopy(&a3, &b3);
}
I somehow think your case use is for embedded programming and I'm not expert. I know in embedded programming you need to decrease both memory usage and code. But you are asking will increase code size obviously.
I have a function that takes a double *result. I am aware that pointers need to be passed by reference in a function. When I call the function void ComputeSeriesPointer(double x, int n, double *result); in main with ComputeSeriesPointer(x, n, &result);, I get the error:
cannot convert ‘double**’ to ‘double*’ for argument ‘3’ to ‘void ComputeSeriesPointer(double, int, double*)’
ComputeSeriesPointer(x, n, &result);
^
When working with pointers, aren't they all passed using the & key? The in class examples were all done this way. Even on the internet things were done this way. Any explanation/clarification would be great.
I am also running this with a c++ compiler (as instructed by my professor) because I am using the pow function.
I'm not sure about what you are doing without seeing the complete code, but If you are doing something like this:
void ComputeSeriesPointer(double, int, double*){
// ...
}
int main(){
double *x = ...;
ComputeSeriesPointer(1.0, 1, &x);
// ...
return 0;
}
Then, the problem is the &x. The & operator is used to extract a variable address. In this case, your variable is already a pointer, so writing &x you are getting a "pointer to pointer", in other words, a double**. That's your problem. Call your function in this way: ComputeSeriesPointer(1.0, 1, x)
The function is expecting you to pass the memory address of an actual double variable, not the memory address of a double* pointer variable:
double result; // NOT double*!
ComputeSeriesPointer(x, n, &result);
You can also do this:
double result; // NOT double*!
double *presult = &result;
ComputeSeriesPointer(x, n, presult);
The error message implies that the type of result is already double *. You don't need to use the & operator if the variable is already a pointer of the appropriate type. So you should do
ComputeSeriesPointer(x, n, result);
Either that, or you need to change the declaration of the result variable in the caller from double * to double.
It is likely that you are doing this:
double *myNewResult;
...
ComputeSeriesPointer(x, n, &myNewResult);
By doing this you are passing the address of a double* not double. You dont need double *myNewResult, just double myNewResult. Or if you need myNewResult to be a double* you can just pass it to the function like this:
ComputeSeriesPointer(x, n, myNewResult);
The function is declared like
void ComputeSeriesPointer(double, int, double*);
its third parameter has type double *
But you call the function like
ComputeSeriesPointer(x, n, &result);
where the third argument has type double **
You need to call the function like
ComputeSeriesPointer(x, n, result);
Or change the function declaration and correspondingly its definition such a way that the third parametr had type double **
void ComputeSeriesPointer(double, int, double **);
Passing a pointer into a function is passing by reference; the pointer is the "reference." (C++ muddied waters a little bit by also introducing a "reference" type which pretends it is not a pointer, but that's not relevant to the code example you've given.)
The & operator means "address of." It takes a thing and returns a pointer to that thing. So,
double x = 1; // this is a double
double *pointer_to_x = &x;
double **pointer_to_pointer_to_x = &pointer_to_x;
and so on.
We need to see a little bit more of your code calling ComputeSeriesPointer() to answer properly, but my guess is that you have:
double *result; // this kind of variable stores *the address of* a double-precision number.
ComputeSeriesPointer( x, n, &result );
but you really want:
double result; // this kind of variable stores a double-precision number.
ComputeSeriesPointer( x, n, &result );
so that you are passing in the address that you want ComputeSeriesPointer() to write a result into.
My actual question is it really possible to compare values contained in two void pointers, when you actually know that these values are the same type? For example int.
void compVoids(void *firstVal, void *secondVal){
if (firstVal < secondVal){
cout << "This will not make any sense as this will compare addresses, not values" << endl;
}
}
Actually I need to compare two void pointer values, while outside the function it is known that the type is int. I do not want to use comparison of int inside the function.
So this will not work for me as well: if (*(int*)firstVal > *(int*)secondVal)
Any suggestions?
Thank you very much for help!
In order to compare the data pointed to by a void*, you must know what the type is. If you know what the type is, there is no need for a void*. If you want to write a function that can be used for multiple types, you use templates:
template<typename T>
bool compare(const T& firstVal, const T& secondVal)
{
if (firstVal < secondVal)
{
// do something
}
return something;
}
To illustrate why attempting to compare void pointers blind is not feasible:
bool compare(void* firstVal, void* secondVal)
{
if (*firstVal < *secondVal) // ERROR: cannot dereference a void*
{
// do something
}
return something;
}
So, you need to know the size to compare, which means you either need to pass in a std::size_t parameter, or you need to know the type (and really, in order to pass in the std::size_t parameter, you have to know the type):
bool compare(void* firstVal, void* secondVal, std::size_t size)
{
if (0 > memcmp(firstVal, secondVal, size))
{
// do something
}
return something;
}
int a = 5;
int b = 6;
bool test = compare(&a, &b, sizeof(int)); // you know the type!
This was required in C as templates did not exist. C++ has templates, which make this type of function declaration unnecessary and inferior (templates allow for enforcement of type safety - void pointers do not, as I'll show below).
The problem comes in when you do something (silly) like this:
int a = 5;
short b = 6;
bool test = compare(&a, &b, sizeof(int)); // DOH! this will try to compare memory outside the bounds of the size of b
bool test = compare(&a, &b, sizeof(short)); // DOH! This will compare the first part of a with b. Endianess will be an issue.
As you can see, by doing this, you lose all type safety and have a whole host of other issues you have to deal with.
It is definitely possible, but since they are void pointers you must specify how much data is to be compared and how.
The memcmp function may be what you are looking for. It takes two void pointers and an argument for the number of bytes to be compared and returns a comparison. Some comparisons, however, are not contingent upon all of the data being equal. For example: comparing the direction of two vectors ignoring their length.
This question doesn't have a definite answer unless you specify how you want to compare the data.
You need to dereference them and cast, with
if (*(int*) firstVal < *(int*) secondVal)
Why do you not want to use the int comparison inside the function, if you know that the two values will be int and that you want to compare the int values that they're pointing to?
You mentioned a comparison function for comparing data on inserts; for a comparison function, I recommend this:
int
compareIntValues (void *first, void *second)
{
return (*(int*) first - *(int*) second);
}
It follows the convention of negative if the first is smaller, 0 if they're equal, positive if the first is larger. Simply call this function when you want to compare the int data.
yes. and in fact your code is correct if the type is unsigned int. casting int values to void pointer is often used even not recommended.
Also you could cast the pointers but you have to cast them directly to the int type:
if ((int)firstVal < (int)secondVal)
Note: no * at all.
You may have address model issues doing this though if you build 32 and 64 bits. Check the intptr_t type that you could use to avoid that.
if ((intptr_t)firstVal < (intptr_t)secondVal)
I have a function that takes a pointer to a floating point array. Based on other conditions, I know that pointer is actually pointing to a 2x2 OR 3x3 matrix. (in fact the memory was initially allocated as such, e.g. float M[2][2] ) The important thing is I want to make this determination in the function body, not as the function argument.
void calcMatrix( int face, float * matrixReturnAsArray )
{
// Here, I would much rather work in natural matrix notation
if( is2x2 )
{
// ### cast matrixReturnAsArray to somethingAsMatrix[2][2]
somethingAsMatrix[0][1] = 2.002;
// etc..
}
else if(is3x3)
{ //etc...
}
}
I am aware that I could use templates and other techniques to better address this problem. My question is really about how to make such a cast at the ### comment. Working in C++.
float (*somethingAsMatrix)[2] = (float (*)[2]) matrixReturnAsArray;
float * could point to the first element of an array of floats, and ought to be reinterpret_castable to that array type. And the result of that cast could point to the first element of a float [][] and so should be reinterpret_castable to that type, and so on. You ought to be able to compose such casts and just directly do
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(matrixReturnAsArray);
An argument of the type float ** is not the same and should not be used this way.
To avoid undefined behavior the pointer must originate from an actual multi-dimensional array, and if the float* is used directly you cannot access more than the first row of the multi-dimensional matrix.
void foo(float *f) {
f[3] = 10.;
float (&arr)[2][2] = *reinterpret_cast<float (*)[2][2]>(f);
arr[1][1] = 10.;
}
void main() {
float a[2][2];
foo(&a[0][0]); // f[3] = 10.; is undefined behavior, arr[1][1] = 10. is well defined
float b[4];
foo(&b[0]); // f[3] = 10.; is well-defined behavior, arr[1][1] = 10. is undefined
}
Given float arr[2][2]; nothing guarantees that &arr[0][1] + 1 is the same as &arr[1][0], as far as I have been able to determine. So although you can use a single dimensional array as a multi-dimensional array by doing f[i*width + j] you cannot treat a multi-dimensional array like a single dimensional array.
It's better to use C++'s compile-time type-safety instead of just relying on not accidentally passing the wrong thing or performing the wrong reinterpret_cast. To get type-safety using raw-arrays you should use references to the raw array type you want:
void foo(float (&f)[2][2]) {}
void foo(float (&f)[3][3]) {}
If you want to pass arrays by value you can't use raw arrays and should instead use something like std::array:
void foo(std::array<std::array<float,2>,2> f) {}
void foo(std::array<std::array<float,3>,3> f) {}
This sort of casting is always cleaner, and easier to deal with, with a judicious use of typedef:
typedef float Matrix_t[2][2];
Matrix_t* someThingAsMatrix = (Matrix_t*) matrixReturnAsArray;
If this is C++ and not C, though, you should create a matrix class. (Or better yet, look for an open source one.)
If I am right:
typedef float Matrix_t[2][2];
Matrix_t &matrix = *(Matrix_t *)matrixReturnAsArray;
or
float (&matrix2)[2][2] = *(float ( *)[2][2])matrixReturnAsArray;
In C there is only the way with the pointer
Matrix_t *someThingAsMatrix = (Matrix_t *)matrixReturnAsArray;
and access via:
(*someThingAsMatrix)[1][0] = ...
I have a class with a 2D array of ints implemented as an int**. I implemented an accessor function to this 2D array as follows, returning a const int** to prevent the user from being able to edit it:
const int** Class::Access() const
{
return pp_array;
}
But I got the compilation error "invalid conversion from int** to const int**". Why is a promotion to const not allowed here? How can I give the user access to the information without editing rights?
Greyson is correct that you'll want to use const int* const*, but didn't explain why your original version failed.
Here is a demonstration of why int** is incompatible with const int**:
const int ci = 0;
const int* pci = &ci;
int* pi;
int** ppi = π
const int** ppci = ppi; // this line is the lynchpin
*ppci = pci;
*pi = 1; // modifies ci!
I was mistaken about the constness of the method being the reason for the error. As Ben points out, the const-ness of the method is irrelavent, since that applies only to the value of the exterior pointer [to pointers to ints], which can be copied to a mutable version trivially.
In order to protect the data (which is your preferred outcome) you should make both the ints and the pointers to ints constant:
int const * const * Class::Access() const
{
return pp_array;
}
Will work.
If you prefer to have the const in front you can also write the declaration like so:
const int * const * Class::Access() const;
but since the second const applies to the pointers, it must be placed to the right (like the const which applies to the method) of the asterisk.