- Please read the following about our future - 1 Update
- void** casting - 8 Updates
- sin/cos with constexpr - 1 Update
maddoxr@acm.org: Sep 15 10:21AM -0700 On Monday, September 14, 2015 at 6:09:32 PM UTC-4, Ramine wrote: > http://waitbutwhy.com/2015/01/artificial-intelligence-revolution-2.html > Thank you, > Amine Moulay Ramdane. Wow! Far off topic, but so interesting there should be no complaint. :-) Randy. |
"Öö Tiib" <ootiib@hot.ee>: Sep 14 06:42PM -0700 On Monday, 14 September 2015 21:26:45 UTC+3, mark wrote: > I'm stuck with using that C library. Converting the data structures to > C++ ones is not an option. > How unsafe is it? When you know that exactly S1* is (implicit or static_) cast to void* then it is guaranteed to be safe to cast it back. Casting pointers to arrays of pointers you run into territory that standard does not guarantee: "A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other." So it does not say that void and struct pointer have same requirements. When you don't know if void pointers and struct pointers have same size and alignment requirements then you can at least static assert that. static_assert( alignof(void*)==alignof(S1*) && sizeof(void*)==sizeof(S1*) , "We need to cast between void** and S1** here!" ); I do not know any way to static assert any bitwise representation however since 'reinterpret_cast' is not required to work compile time. Bitwise representation is same on all implementations I know of to make the casts cheap for C programs so it is perhaps risk worth taking being stuck like you describe. |
Jorgen Grahn <grahn+nntp@snipabacken.se>: Sep 15 09:01AM On Mon, 2015-09-14, Martin Shobe wrote: >> Is it safe to cast Vector::data to S1** / S2**? > Technically no. Even getting data to point to an array of S1* or S2* is > already a problem. Aren't we talking about two different things? void** foo = something_with_S1(); S1* s1 = static_cast<S1*>(foo[0]); // ok, if you're sure there are // S1 objects there S2* s2 = static_cast<S2*>(foo[0]); // not ok S1** bar = static_cast<S1**>(foo); // error That last line was what the OP asked for. And it doesn't even compile -- I have to replace it with a C-style cast (or maybe reinterpret_cast would be enough?) I think of it as if sizeof(void*) may be larger than sizeof(S1*). > However, chances are if it works in that direction, > it will work in reverse and I don't see any better options. (Assuming > you can't fix the C library.) If he really needs an array of S1*, he could also copy into one, element by element. /Jorgen -- // Jorgen Grahn <grahn@ Oo o. . . \X/ snipabacken.se> O o . |
mark <mark@invalid.invalid>: Sep 15 01:36PM +0200 The void** casting is a bit close to UB, so I'll probably avoid that. I've come up with a nice kludge to wrap the C vector with zero overhead (GCC optimizes the C++ wrapper completely away). This should have well-defined behavior with C++11. #include <boost/iterator/transform_iterator.hpp> #include <iostream> #include <memory> typedef struct { void** data; unsigned int length; } Vector; typedef struct { int i; } S1; typedef struct { const char* s; } S2; static const int elem_count = 5; static const char* int_str[] = {"0", "1", "2", "3", "4"}; void initTestVecS1(Vector& vec) { vec.data = static_cast<void**>(malloc(sizeof(void*) * elem_count)); vec.length = elem_count; for(int i = 0; i < elem_count; i++) { vec.data[i] = new S1{i}; } } void initTestVecS2(Vector& vec) { vec.data = static_cast<void**>(malloc(sizeof(void*) * elem_count)); vec.length = elem_count; for(int i = 0; i < elem_count; i++) { vec.data[i] = new S2{int_str[i]}; } } template<typename node_type> node_type& cast_node(void* ptr) { return *static_cast<node_type*>(ptr); } template<typename node_type> struct VectorWrapper { Vector data; auto begin() { return boost::make_transform_iterator( &data.data[0], cast_node<node_type>); } auto end() { return boost::make_transform_iterator( &data.data[data.length], cast_node<node_type>); } static VectorWrapper<node_type>& toWrapper(Vector& vec) { return *reinterpret_cast<VectorWrapper<node_type>*>(&vec); } }; int main() { Vector v1; initTestVecS1(v1); auto vw1 = VectorWrapper<S1>::toWrapper(v1); for(int i = 0; i < elem_count; i++) std::cout << static_cast<S1*>(v1.data[i])->i << " "; std::cout << std::endl; for(const auto& elem : vw1) std::cout << elem.i << " "; std::cout << std::endl; Vector v2; initTestVecS2(v2); auto vw2 = VectorWrapper<S2>::toWrapper(v2); for(const auto& elem : vw2) std::cout << elem.s << " "; std::cout << std::endl; } |
Martin Shobe <martin.shobe@yahoo.com>: Sep 15 08:10AM -0500 On 9/15/2015 4:01 AM, Jorgen Grahn wrote: >> Technically no. Even getting data to point to an array of S1* or S2* is >> already a problem. > Aren't we talking about two different things? To a certain degree. The comments above are directed more to the situation itself, as opposed to what can be done to retrieve the asked for information. To the best of my knowledge, neither C nor C++ make any provisions for passing around arrays of S1 * (or S2 *) as arrays of void *. > void** foo = something_with_S1(); > S1* s1 = static_cast<S1*>(foo[0]); // ok, if you're sure there are > // S1 objects there No, even this isn't certain to be ok. It's ok if the array is an array void * that happen to point to S1 objects. But the original description is that it's an array of S1 *. (In all fairness, it's about as likely to work as the last line, but neither C nor C++ require it to.) > S2* s2 = static_cast<S2*>(foo[0]); // not ok > S1** bar = static_cast<S1**>(foo); // error > That last line was what the OP asked for. Yes, and that's what I was talking about (except, as you note later, it would need a c-style or reinterpret_cast). > -- I have to replace it with a C-style cast (or maybe > reinterpret_cast would be enough?) > I think of it as if sizeof(void*) may be larger than sizeof(S1*). There are other potential issues as well. >> you can't fix the C library.) > If he really needs an array of S1*, he could also copy into one, > element by element. At this point, even that isn't certain to work. Martin Shobe |
mark <mark@invalid.invalid>: Sep 15 03:59PM +0200 On 2015-09-15 15:10, Martin Shobe wrote: > void * that happen to point to S1 objects. But the original description > is that it's an array of S1 *. (In all fairness, it's about as likely to > work as the last line, but neither C nor C++ require it to.) The original description is sloppy. It's not strictly an array of S1*, but rather an array of void* which point to S1. The array is allocated for the proper void** size and accessed in line with those static_casts. So the void* <-> S1* conversion magic happens. |
scott@slp53.sl.home (Scott Lurndal): Sep 15 02:48PM >but rather an array of void* which point to S1. >The array is allocated for the proper void** size and accessed in line >with those static_casts. So the void* <-> S1* conversion magic happens. In any case, on any architecture that matters for C++ programming, an array of pointers is an array of pointers whether they're pointers to void or pointers to an object. Leaving aside the standard and UB, casting (using reinterpret_cast or c-style casting) "void **" to "S1 **" will work correctly. |
Martin Shobe <martin.shobe@yahoo.com>: Sep 15 10:39AM -0500 On 9/15/2015 8:59 AM, mark wrote: >> work as the last line, but neither C nor C++ require it to.) > The original description is sloppy. It's not strictly an array of S1*, > but rather an array of void* which point to S1. Then the cast above is ok, and what I would recommend. Even if Scott Lurndal is correct in his response, it's better to not make that assumption unless there's a significant gain. For most uses, it's too easy to wrap in something that does the correct thing for there to be a significant gain. Martin Shobe |
mark <mark@invalid.invalid>: Sep 15 06:44PM +0200 On 2015-09-15 17:39, Martin Shobe wrote: > assumption unless there's a significant gain. For most uses, it's too > easy to wrap in something that does the correct thing for there to be a > significant gain. I'm happy with the C++ wrapper I posted - no overhead (and no UB according to my reading of the standard). Having been burned by aggressive standard interpretations of UB that GCC has done in the past (resulting in miscompiled code), I try to avoid grey areas. |
Nobody <nobody@nowhere.invalid>: Sep 15 08:05AM +0100 On Mon, 14 Sep 2015 21:20:52 +0200, Christian Gollwitzer wrote: >> Another option is a recursive approach based upon the sum/difference >> formulae and half-angle formulae. > which is usually called the CORDIC algorithm. They're different algorithms. CORDIC is based upon adding or subtracting angles of the form arctan(1/(2^n)); the half-angle approach uses angles of the form pi/(2^n). CORDIC is more efficient on simple hardware, as it only requires shift, add/subtract, and a lookup table. Half-angle doesn't require the lookup table, but it does require square roots. But std::sqrt() doesn't appear to be constexpr either, so you'd need to implement that as well. The main advantage of half-angle over CORDIC or a Taylor series is that it doesn't require a set of constants whose number and accuracy needs to change according to the desired accuracy of the result. Although that probably doesn't matter here. |
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page. To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com. |
No comments:
Post a Comment