[SOLVED] C++: which type of cast is best for audio callbacks?

Programming applications for making music on Linux.

Moderators: MattKingUSA, khz

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Sun Dec 04, 2016 4:23 pm

Sadko4u is an assembly guy, don't listen to his C++ advice. Only use reinterpret_cast if all other casts fail. I only use reinterpret_cast during serialization to get access to raw bytes and C++ guarantees that you can cast a pointer to char*. Almost everything else is UB.

Also, I would suggest to wrap your pointers into some class because pointer arithmetic is extremely unsafe. GSL has span<T> which provides a safe interface over a pointer. My audio library which sadko really really hates uses std::vector.

User avatar
sadko4u
Established Member
Posts: 610
Joined: Mon Sep 28, 2015 9:03 pm

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby sadko4u » Sun Dec 04, 2016 5:04 pm

FaTony wrote:Sadko4u is an assembly guy, don't listen to his C++ advice.

That's true. Assembly is very useful for time-critical operations.

FaTony wrote:Only use reinterpret_cast if all other casts fail. I only use reinterpret_cast during serialization to get access to raw bytes and C++ guarantees that you can cast a pointer to char*. Almost everything else is UB.

And what about such example (?):

Code: Select all

    uint32_t *rgba(uint8_t *ptr)
    {
        return static_cast<uint32_t *>(ptr);
    }

Some library has returned RGBA (for example, cairo) buffer as array of bytes and we want to process a color as single 32-bit integer. C++ fails to static_cast this. But reinterpret_cast succeeds. The main thesis is here: if you understand what data you are processing, you have no troubles to peform type casts.

FaTony wrote:Also, I would suggest to wrap your pointers into some class because pointer arithmetic is extremely unsafe. GSL has span<T> which provides a safe interface over a pointer.

Oh, please, no. Don't do extra work where it is not necessary. Wrap a wrapper that is wrapped by wrapper that wraps a wrapper to the pointer.

FaTony wrote:My audio library which sadko really really hates uses std::vector.

I don't hate it, i just criticize it because it's not optimal because... it's too abstract. Remember 'The Three Big Lies' from video? That's it.

You're C++ guy, you like to write huge templates that 'will solve any needs'. I'm assembly guy, I like to implement algorithms that work at least 3x time faster (and even much faster on bulk data) than the code written with C++ for 'the most important needs'.
LSP (Linux Studio Plugins) Developer and Maintainer.

User avatar
tramp
Established Member
Posts: 1246
Joined: Mon Jul 01, 2013 8:13 am

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby tramp » Sun Dec 04, 2016 5:50 pm

sadko4u wrote:And what about such example (?):

Code: Select all

   uint32_t *rgba(uint8_t *ptr)
    {
        return static_cast<uint32_t *>(ptr);
    }



When you do a type conversation, a reinterpret_cast is perfectly valid, and needed. In fact, that is the reason, why we have the reinterpret_cast in C++. :wink:
But, when no type conversation is needed, using a reinterpret_cast, instead of a static_cast is "bad codding style".
That, exactly, shows the difference, if you know what you do, or not. :wink:
EOF

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Tue Dec 06, 2016 3:52 am

sadko4u wrote:And what about such example (?):

Code: Select all

    uint32_t *rgba(uint8_t *ptr)
    {
        return reinterpret_cast<uint32_t *>(ptr); // Changed this to reinterpret_cast because that's what you're advocating.
    }


UB at it's finest. http://eel.is/c++draft/basic.lval#8
You've just violated a strict aliasing rule.

The standard conforming code would be this:

Code: Select all

std::vector<std::uint32_t> rgba(std::uint8_t* ptr, std::size_t size)
{
   if ((size % 4) != 0)
   {
      throw std::invalid_argument{"rgba: size is invalid."};
   }
   std::vector<std::uint32_t> result;
   result.reserve(size / 4);
   for (std::size_t i = 0; i < size; i += 4)
   {
      std::uint32_t value = static_cast<std::uint32_t>(ptr[i]) << 24 +
         static_cast<std::uint32_t>(ptr[i + 1]) << 16 +
         static_cast<std::uint32_t>(ptr[i + 2]) << 8 +
         ptr[i + 3];
      result.push_back(value);
   }
   return result;
}


Couple of points to note:
  1. Properly qualified types. Almost everything in C++ is inside the namespace std. uint8_t and others become available in global namespace if you include <stdint.h> which is deprecated or type "using namespace std;" which is a bad practice.
  2. I wanted to return std::pair<std::uint32_t*, std::size_t> to keep the raw pointer spirit of original code but quickly found that it would be horrible.
  3. static_cast<std::uint32_t> is important because std::uint8_t would be promoted to int before the shift which is not signed and can be 16 bit wide.

User avatar
sadko4u
Established Member
Posts: 610
Joined: Mon Sep 28, 2015 9:03 pm

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby sadko4u » Tue Dec 06, 2016 9:01 am

FaTony wrote:UB at it's finest. http://eel.is/c++draft/basic.lval#8

While writing such things please explain where did you find UB in the example. C++ can not return pointer to the data interpreted as the same data with the different type? That's sad for such 'powerful' and 'flexible' language.

FaTony wrote:You've just violated a strict aliasing rule.

OK, please show the place where I violated the strict aliasing rule in this short cast example. I'll ask in a bit another form: what's the problem if we don't work with the original pointer?

FaTony wrote:The standard conforming code would be this:

Code: Select all

std::vector<std::uint32_t> rgba(std::uint8_t* ptr, std::size_t size)
{
   if ((size % 4) != 0)
   {
      throw std::invalid_argument{"rgba: size is invalid."};
   }
   std::vector<std::uint32_t> result;
   result.reserve(size / 4);
   for (std::size_t i = 0; i < size; i += 4)
   {
      std::uint32_t value = static_cast<std::uint32_t>(ptr[i]) << 24 +
         static_cast<std::uint32_t>(ptr[i + 1]) << 16 +
         static_cast<std::uint32_t>(ptr[i + 2]) << 8 +
         ptr[i + 3];
      result.push_back(value);
   }
   return result;
}


  1. Properly qualified types. Almost everything in C++ is inside the namespace std. uint8_t and others become available in global namespace if you include <stdint.h> which is deprecated or type "using namespace std;" which is a bad practice.
  2. I wanted to return std::pair<std::uint32_t*, std::size_t> to keep the raw pointer spirit of original code but quickly found that it would be horrible.
  3. static_cast<std::uint32_t> is important because std::uint8_t would be promoted to int before the shift which is not signed and can be 16 bit wide.


Oh man, the better way you should never show this code. You didn't understand right the problem and began to immediately write such unoptimal code. That's sad, because:
  • It does not solve the original problem
  • It uses dynamic allocation of memory
  • It throws exceptions
  • It returns instance to the object in stack, so probably the calling code will call the copy constructor for std::vector to copy data, so you get the second dynamic allocation of memory.
  • It performs some binary math on data that (probably) shouldn't ever be
  • static_cast<std::uint32_t>(ptr[i]) - this is the shame. std::uint32_t(ptr[i]) is shorter and mostly recommended.
  • static_cast<std::uint32_t>(ptr[i]) << 24 + static_cast<std::uint32_t>(ptr[i + 1]) << 16 - this is the shame, too. Because shift operations have lower priority rather than additions, so at the output you'll get bullshit. Also, OR (|) operation works faster at low-level rather than PLUS (+);

As I suggested from previous discussions, you're very bad low-level optimizer.
That's why criticise the library mentioned by you in this topic and never will use it.
LSP (Linux Studio Plugins) Developer and Maintainer.

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Tue Dec 06, 2016 12:39 pm

sadko4u wrote:While writing such things please explain where did you find UB in the example. C++ can not return pointer to the data interpreted as the same data with the different type? That's sad for such 'powerful' and 'flexible' language.

Only char and unsigned char are allowed to alias. std::uint8_t and std::uint32_t are not. Unlike other languages C++ let's you shoot yourself in the foot and do reinterpret_cast.
sadko4u wrote:OK, please show the place where I violated the strict aliasing rule in this short cast example. I'll ask in a bit another form: what's the problem if we don't work with the original pointer?

You don't have the guarantee. It may work on the particular platform but otherwise it may break.
sadko4u wrote:Oh man, the better way you should never show this code. You didn't understand right the problem and began to immediately write such unoptimal code. That's sad, because:
It does not solve the original problem

I thought your problem was to convert bytes to RGBA array. It solves exactly it.
sadko4u wrote:It uses dynamic allocation of memory

How else would you write a function with wide contract? You haven't told us anything else about your function.
sadko4u wrote:It throws exceptions

Yes, because it is idiomatic. Almost all of the standard library uses exceptions.
sadko4u wrote:It returns instance to the object in stack, so probably the calling code will call the copy constructor for std::vector to copy data, so you get the second dynamic allocation of memory.

Wrong. The compiler will perforrn Named Return Value Optimization. If it doesn't, it will call a move constructor. No copy will ever be made.
sadko4u wrote:It performs some binary math on data that (probably) shouldn't ever be

Because you can't do anything else while being standard conforming.
sadko4u wrote:static_cast<std::uint32_t>(ptr[i]) << 24 + static_cast<std::uint32_t>(ptr[i + 1]) << 16 - this is the shame, too. Because shift operations have lower priority rather than additions, so at the output you'll get bullshit. Also, OR (|) operation works faster at low-level rather than PLUS (+);

This is exactly why I avoid writing low level code and prefer to use classes which have a clean, well designed interface.

sadko4u wrote:As I suggested from previous discussions, you're very bad low-level optimizer.

I never claimed to be. I prefer correctness, portability and abstractness first and I design reusable components which can solve many cases.
sadko4u wrote:That's why criticise the library mentioned by you in this topic and never will use it.

I don't care. The common complaint I get is that my libs are [A]GPL and people love to write proprietary software and really hate [A]GPL. I couldn't care about them.

User avatar
sadko4u
Established Member
Posts: 610
Joined: Mon Sep 28, 2015 9:03 pm

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby sadko4u » Tue Dec 06, 2016 1:43 pm

FaTony wrote:I thought your problem was to convert bytes to RGBA array. It solves exactly it.

No! The problem was quite different: we want to interpret RGBA bytes as array of integers, currently without any modifications. What will be done with them after - we don't care.

FaTony wrote:How else would you write a function with wide contract? You haven't told us anything else about your function.

Right! I didn't told anything about function. Because this function just demonstrates that static_cast doesn't work on this example. But this example can be related to the real task that needs to interpret raw data as pointer to beginning of an array of elements of some type.

FaTony wrote:Yes, because it is idiomatic. Almost all of the standard library uses exceptions.

It's not idiomatic, it's idiotic. Because it is not binary-compatible with other environment if the function will be placed in a shared library. Some code imports your library, calls the function and crashes without any possibility to handle the error.

FaTony wrote:Wrong. The compiler will perforrn Named Return Value Optimization. If it doesn't, it will call a move constructor. No copy will ever be made.

Maybe it's true since C++11. In reality I wouldn't ever rely on a compiler.

FaTony wrote:Because you can't do anything else while being standard conforming.

Because the original problem doesn't require any math.

FaTony wrote:This is exactly why I avoid writing low level code and prefer to use classes which have a clean, well designed interface.

This is exactly because of your misunderstanding of platform you're writing for.

FaTony wrote:I never claimed to be. I prefer correctness, portability and abstractness first and I design reusable components which can solve many cases.

This is a common problem of C++ developers. They often write 'common code' and fight with templates instead of doing something useful. The availability to write nine-floor templates (and get tons of generated machine code, lol) and decrypt multi-screen error messages raises the feeling of self-importance. But! It's not a target. You're not writing code because you need to write it. You write the code to solve the specific problem, not for the show 'the most beautiful compilation unit'.

FaTony wrote:I don't care. The common complaint I get is that my libs are [A]GPL and people love to write proprietary software and really hate [A]GPL. I couldn't care about them.

This is bullshit. How is the quality of code relative to licensing policy?

UPD: About three big lies
LSP (Linux Studio Plugins) Developer and Maintainer.

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Tue Dec 06, 2016 2:25 pm

sadko4u wrote:No! The problem was quite different: we want to interpret RGBA bytes as array of integers, currently without any modifications. What will be done with them after - we don't care.

Well, if you don't mind a "bomb" pointer that will lead to UB and the 1st dereference - fine. Loads the gun and point it at foot and let the user pull the trigger.

sadko4u wrote:Right! I didn't told anything about function. Because this function just demonstrates that static_cast doesn't work on this example. But this example can be related to the real task that needs to interpret raw data as pointer to beginning of an array of elements of some type.

Again, if the task of reinterpreting raw data occurs in the first place, then the design is deeply flawed. Good interface will be type safe where you never need a reinterpret_cast.

sadko4u wrote:It's not idiomatic, it's idiotic. Because it is not binary-compatible with other environment if the function will be placed in a shared library. Some code imports your library, calls the function and crashes without any possibility to handle the error.


C++ ABI compatibility is almost nonexistent. You will need to use the same compiler version and switches to be ABI compatible, Gentoo way.

sadko4u wrote:Maybe it's true since C++11. In reality I wouldn't ever rely on a compiler.


Then why do you bother with C++ at all? Go write assembly and be happy.

sadko4u wrote:This is a common problem of C++ developers. They often write 'common code' and fight with templates instead of doing something useful. The availability to write nine-floor templates (and get tons of generated machine code, lol) and decrypt multi-screen error messages raises the feeling of self-importance. But! It's not a target. You're not writing code because you need to write it. You write the code to solve the specific problem, not for the show 'the most beautiful compilation unit'.


I got very tired after writing the same algorithms many times because every game decided to invent their own scripting language. That's why I chose C++.

sadko4u wrote:This is bullshit. How is the quality of code relative to licensing policy?

Because people first look at the license. I'm pretty sure nobody who has complained about GPL had seen the code.

sadko4u wrote:UPD: About three big lies


I love that this site got an explanation why your code has UB.

User avatar
sadko4u
Established Member
Posts: 610
Joined: Mon Sep 28, 2015 9:03 pm

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby sadko4u » Tue Dec 06, 2016 6:07 pm

FaTony wrote:Well, if you don't mind a "bomb" pointer that will lead to UB and the 1st dereference - fine. Loads the gun and point it at foot and let the user pull the trigger.

This 'bomb' pointer is returned from third-party library and I have to do something with it. Why do you frustrate?

FaTony wrote:Again, if the task of reinterpreting raw data occurs in the first place, then the design is deeply flawed. Good interface will be type safe where you never need a reinterpret_cast.

You mean that design of JACK interface is deeply flawed? I don't think so.

sadko4u wrote:C++ ABI compatibility is almost nonexistent. You will need to use the same compiler version and switches to be ABI compatible, Gentoo way.

Don't think that your shared library will be used by programs written in C++ only. That's not true.

FaTony wrote:Then why do you bother with C++ at all? Go write assembly and be happy.


I'm not too dumb to write all in assembly code. Assembly should be used to optimize performance-critical parts of program. But compiler is not a magic pill, it can solve only 5-10% of job that should solve the developer.

FaTony wrote:I got very tired after writing the same algorithms many times because every game decided to invent their own scripting language. That's why I chose C++.

The same can be told about different languages: 'that's why I chose Perl' or 'That's why I chose Lua' or 'That's why I chose Python'. It's not an argument.

sadko4u wrote:Because people first look at the license. I'm pretty sure nobody who has complained about GPL had seen the code.

Oh, dear, license is the second thing what people are watching for.

FaTony wrote:I love that this site got an explanation why your code has UB.

The link doesn't work. You still didn't explain why my code has UB. The ghost of UB is flying somewhere but still there are no facts.
LSP (Linux Studio Plugins) Developer and Maintainer.

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Tue Dec 06, 2016 8:31 pm

sadko4u wrote:This 'bomb' pointer is returned from third-party library and I have to do something with it. Why do you frustrate?


Then I would change the library.

sadko4u wrote:You mean that design of JACK interface is deeply flawed? I don't think so.

Although it is better than std::uint8_t*, void* highlights how C API is always type unsafe and hacky. I try to avoid C APIs at all costs.

sadko4u wrote:Don't think that your shared library will be used by programs written in C++ only. That's not true.


I don't care about C. I pass all kinds of classes and exceptions through my API. Want C? Don't use my code.

sadko4u wrote:Oh, dear, license is the second thing what people are watching for.


Dunno, I always look at license before looking at the code. If it's proprietary, I never look at it again.

sadko4u wrote:The link doesn't work. You still didn't explain why my code has UB. The ghost of UB is flying somewhere but still there are no facts.


http://cellperformance.beyond3d.com/art ... asing.html

The UB is when you try to access the same memory location from incompatible types.

User avatar
sadko4u
Established Member
Posts: 610
Joined: Mon Sep 28, 2015 9:03 pm

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby sadko4u » Tue Dec 06, 2016 9:56 pm

FaTony wrote:Then I would change the library.

Nuff said. I can call this case only 'C++ of the entire cerebral system'.

sadko4u wrote:Although it is better than std::uint8_t*, void* highlights how C API is always type unsafe and hacky. I try to avoid C APIs at all costs.

C is designed as low-level language. It's design is done so that you easily can translate each instruction into assembly code in mind. C++ is an attempt to mix low-level language with high-level paradigm keeping mostly all low-level tricks from C. What we get now - an ugly language that fall into hacky metaprogramming stage because there are no built-in mechanisms to combine memory allocation, construction/destruction, exception handling etc without writing tons of templated code. That's why I reject all new features of C++ and use it mostly as 'advanced C with some syntax sugar'.

FaTony wrote:I don't care about C. I pass all kinds of classes and exceptions through my API. Want C? Don't use my code.

Alright, alright. Keep inventing your bicycle.

FaTony wrote:Dunno, I always look at license before looking at the code. If it's proprietary, I never look at it again.

Don't speak about people as if they were you. People are not idiots and they are seeking for proper solutions, event if they cost some tons of money.

FaTony wrote:The UB is when you try to access the same memory location from incompatible types.

Where in my example I DO access the same memory location from incompatible types?
LSP (Linux Studio Plugins) Developer and Maintainer.

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Wed Dec 07, 2016 1:04 pm

sadko4u wrote:What we get now - an ugly language that fall into hacky metaprogramming stage because there are no built-in mechanisms to combine memory allocation, construction/destruction, exception handling etc without writing tons of templated code.


You can easily write code without templates, it will work for your case only. Templates are needed if you want to use different types but have the same algorithms.

sadko4u wrote:Where in my example I DO access the same memory location from incompatible types?


Ok, the lawyer mode. You didn't dereference the pointer in your code. But I don't think there is any useful value in a pointer that can't be derefenced. Your function should be called MakeUselessPointer.

User avatar
sadko4u
Established Member
Posts: 610
Joined: Mon Sep 28, 2015 9:03 pm

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby sadko4u » Wed Dec 07, 2016 3:33 pm

FaTony wrote:You can easily write code without templates, it will work for your case only. Templates are needed if you want to use different types but have the same algorithms.

I already do so. And I doubt that in nearest 10 years audio samples will be present in other form rather than in float or double format. Because floating-point format has a lot of advantages relative to the fixed-point format. So there is no need to generalize sample to the template argument. It doesn't yield to optimal code generation that is required for DSP.

FaTony wrote:Ok, the lawyer mode. You didn't dereference the pointer in your code.

You may call it as you wish. Without context around the code it's not possible to say, is UB there or not. Also, if there is no access to the data via original pointer, there is no UB at all.

FaTony wrote:But I don't think there is any useful value in a pointer that can't be derefenced. Your function should be called MakeUselessPointer.

Let me repeat again: this function is written to demonstrate that static_cast won't work in this context.
LSP (Linux Studio Plugins) Developer and Maintainer.

User avatar
Lyberta
Established Member
Posts: 650
Joined: Sat Nov 01, 2014 8:15 pm
Location: The Internet
Contact:

Re: [SOLVED] C++: which type of cast is best for audio callbacks?

Postby Lyberta » Wed Dec 07, 2016 4:01 pm

I'm tired. Go continue having UB, I don't care anymore.


Return to “Developer's Section”

Who is online

Users browsing this forum: No registered users and 1 guest