Register a SA Forums Account here!
JOINING THE SA FORUMS WILL REMOVE THIS BIG AD, THE ANNOYING UNDERLINED ADS, AND STUPID INTERSTITIAL ADS!!!

You can: log in, read the tech support FAQ, or request your lost password. This dumb message (and those ads) will appear on every screen until you register! Get rid of this crap by registering your own SA Forums Account and joining roughly 150,000 Goons, for the one-time price of $9.95! We charge money because it costs us money per month for bills, and since we don't believe in showing ads to our users, we try to make the money back through forum registrations.
 
  • Post
  • Reply
PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Question about replacing macros, static analysis tools hate (most of) them for good reason, but I'm unsure of what the best replacement is. Define a bunch of static inline functions for all required types, possibly with a macro'd _generic access, or a single templated version? Does it even matter?

Adbot
ADBOT LOVES YOU

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Xarn posted:

What kind of macros? What are they doing?

Mostly basic stuff, min, max, abs, squares, cubes, root sum squares.

Things that could be and should be done in real functions, but I'm mostly curious if there's a performance cost of switching them to templates.

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Foxfire_ posted:

Doing something like

char aBigDataBuffer[4096];
SomeStruct* someStruct = (SomeStruct*)aBigDataBuffer;

is more likely to happen to work, but it's violating assumptions in the optimizer even if you make all the alignment issues work out. You may end up with behavior where changes in the buffer are sometimes not reflected in the struct (because the optimizer can assume that changing a char[] doesn't invalidate previous reads of a SomeStruct's fields because they're different types)

lol wait is this not actually legal/well defined? our I/O code does this all over the place

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Foxfire_ posted:

Yep, that's undefined behavior.

The legal way to do it is to do a memcpy() because char* pointers are permitted to alias anything (but not the reverse).
A good optimizer will often eliminate the actual copy, but if you're stuck with a less fancy compiler you end up having to decide between technically wrong code (that will probably work if your optimizer isn't sophisticated enough to use those aliasing assumptions anyway) or extra copies and temporary space

Example with gcc eliding a memcpy()

Very interesting. I mean we do know it works, but no wonder the static analysis tools we recently implemented is so grumpy about it :v:

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Okay so going back to the question of pulling data from a char buffer, what's the best way to actually handle something like this?


code:
char acDataBuffer[4096];

typedef struct
{
   double dData1;
   long lData2;
   double dData3;	// Note, this will not fall on a 8-byte boundary and so padding will be inserted prior
   ...
} DataStruct;
I'm going to receive data in acDataBuffer, and it will be packed according to the order shown in DataStruct, minus the 4 padding bytes that will be inserted between lData2 and dData3. That padding means I can't cleanly memcpy from the buffer into a local struct (without adding pragma pack directives), nor do I have control over the input data, so I can't re-order it to avoid padding.

Currently this is actually handled in the code by declaring DataStruct with a bunch of char arrays instead of the full types, and then just casting it into the full type when required, as below (with simplified operations of course, these do need to be accessed separately):
code:
typedef struct
{
   char acData1[8];
   char acData2[4];
   char acData3[8];
   ...
} CharDataStruct;

void func(char* acCharBuffer)
{
   CharDataStruct* pstData = (CharDataStruct*)acCharBuffer;
   
   double dCombinedData = *(double*)(pstData->acData1) + *(double*)(pstData->acData3);
}
The above code works just fine, but it freaks our static analysis tool right the gently caress out every time we cast a char pointer to a pointer with greater alignment requirements.

The options as I see it are:
  1. pragma pack the version of DataStruct that uses the full data types to avoid padding, and memcpy into a local copy of that struct, then access each variable normally.
  2. Individually memcpy each of the data members out of the char version of the struct (which I am trying to avoid as it will look really messy, there's actually 16 variables in that struct)

Is there a serious argument to made for one approach over the other?

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Very helpful, thanks for the input all!

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

well it's late and I've been drinking, but your voidbutt is a pointer to a char pointer. Just dereference with char* pcGoodPointer = *(char**)voidbutt

E: oh right you have to cast it first, can't dereference void directly.

E2: Or just dereference twice?
char** ppcFoo = voidbutt;
printf("\nfirst char in string: %c", **ppcFoo);

PittTheElder fucked around with this message at 04:39 on Sep 24, 2021

Adbot
ADBOT LOVES YOU

PittTheElder
Feb 13, 2012

:geno: Yes, it's like a lava lamp.

Strong Sauce posted:

Thanks everyone for your sympathetic words. I kinda avoided this thread today because I was pretty exhausted from dealing with C++ at work that I wrote that out of frustration and didn't want to deal with anything C++ today.

I do feel like I'm a bit too old to be putting so much more esoteric knowledge into my brain. I'm stalling a bit in my career right now and I honestly don't know if trying to become an expert on C++ is the thing that reinvigorates my enjoyment of programming or of my job. There are probably lucrative jobs to be had with this skillset but I do not have the mathematical chops to do game programming, and I can't imagine Enterprise C++ apps are any better than Enterprise Java apps.

I guess it also doesn't help that we're basically supporting multiple platforms off the bat, and dealing with all the issues between each system, and that we're also reducing the team in half because we're having to reallocate resources.

I'll look into this.. maybe get my employer to buy these books.

Just get a job doing embedded systems development with a company like mine who still uses C++99, we don't have to deal with any of that poo poo :v:

  • 1
  • 2
  • 3
  • 4
  • 5
  • Post
  • Reply