Is there a standards-compliant way to create zero-copy IPC in C ++?

I have an application that is currently reading data from a stream (socket, named, pipe, stdin, whatever) into a buffer char

and then uses reinterpret_cast

to point a Foo *

(where Foo

is POD) to the middle of the buffer, and then works with the contents of the buffer through this pointer.

This now violates strict alias rules, although I doubt it would actually cause a problem in practice. That said, is there an acceptable way to do this in standard C ++? Since we are potentially transferring 100 gigabytes in this way and do not want to under any circumstances introduce the overhead of copying this data from the buffer to the structure using memcpy

.

To be clear, the code looks something like this:

MessageData *msg = new MessageData();
while (ipc.we_have_data()) {
   ipc.read(msg);
   char *buf = msg->data();
   Header *h = reinterpret_cast<Header *>(buf);
   if (h->tag == 0) {
      Payload *p = reinterpret_cast<Payload *>(buf + sizeof(Header));
      do_stuff_with_payload(p);
   } else if (h->tag == 1) {
      // etc...
   }
}

      

I understand there may be alignment issues, but I'm not interested in them at the moment. The data is generated on the same platform by the same compiler, so there is no problem with the layout of structure elements. But as I understand it, this technically violates the strict alias rules.

Is there an efficient way to do this without breaking the strict alias rules?

Or am I completely wrong and is it just fine by these rules?

If so, why?

Edit: A deleted comment pointed to this definition of alias rules , which says it char *

gets a free pass. So my example doesn't actually violate the strict alias rules. Does anyone know the correct part of the standard for this?

+3


source to share


2 answers


Unfortunately, the standard is not very friendly for handling structured data read into a character buffer. Only the opposite is allowed: if you know you are going to read a POD object, you can build it and pass its address converted to a char pointer to any function that can fill it with actual data, then use it as usual.

The free pass provided char *

only allows the object to be processed at the byte level, but the strict anti-aliasing rule generally prohibits it from deciding that the char buffer actually contains the object. In any case, the higher risk here would be an alignment issue.



Otherwise, it is perfectly legal for specific compiler implementations to ignore the strict aliasing rule. Then undefined happens by the standard, but can be perfectly determined by the compiler if you pass it the appropriate flag. Your program may then break with a different compiler, or a different configuration of the same compiler, so it will have portability issues, but that might be acceptable if it is clearly documented - and you're sure an alignment issue can't occur ...

+1


source


Since you are targeting a (presumably) embedded platform with well-known characteristics and well-defined behavior, you can make an informed decision to disable strong alias with -fno-strict-aliasing

. Undefined behavior is simply not portable behavior that, if defined, pessimizes certain systems proactively.



If you really need to follow the standard, using union is your best bet. You can try C ++ - if need be, going for some kind of specialized type-to-type union that doesn't do any allocations, or doesn't use any span / view class that can take a pointer to a char buffer but wraps your PODs- specific API.

0


source







All Articles