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
LLSix
Jan 20, 2010

The real power behind countless overlords

Jabor posted:

My guess would be it's some kind of "sort by A, then B, then C", and they only want to switch the direction of one of those comparisons.

Pretty much. A is reversible, but B needs a little more finagling.

Adbot
ADBOT LOVES YOU

rjmccall
Sep 7, 2007

no worries friend
Fun Shoe
There’s also qsort_r that forwards a context down to the comparator.

Xarn
Jun 26, 2015

LLSix posted:

Pretty much. A is reversible, but B needs a little more finagling.

Just use stablesort and sort step by step.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

rjmccall posted:

There’s also qsort_r that forwards a context down to the comparator.

I was going to suggest that but then I got the poster mixed up with the goon still using Borland C or whatever for their course.

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
Has anybody seen and tried some strategies for getting mocks into unit tests for C code? Not C++, but C. I can't really imagine doing it thoroughly without devolving into some kind of macro hell. But who knows, maybe there's some compiler-specific moon beams or something.

Jabor
Jul 16, 2010

#1 Loser at SpaceChem
Fundamentally you just want to link against a mock implementation of your dependency instead of the real implementation, right?

I guess it gets complicated if you want your mock implementation to pass through to the real impl under some conditions.

more falafel please
Feb 26, 2005

forums poster

You could do an ad-hoc implementation of vtables with function pointers.

Sweeper
Nov 29, 2007
The Joe Buck of Posting
Dinosaur Gum

Rocko Bonaparte posted:

Has anybody seen and tried some strategies for getting mocks into unit tests for C code? Not C++, but C. I can't really imagine doing it thoroughly without devolving into some kind of macro hell. But who knows, maybe there's some compiler-specific moon beams or something.

for prod:
-lprod_version

for test:
-lmock_version

or, we just impl whatever function we need in the test itself if it is small/configuration. #include the header, implement the function, no link needed and mock is embedded right next to test

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
I'll accept some clever linking as a way around macro hell. Although:

Jabor posted:

I guess it gets complicated if you want your mock implementation to pass through to the real impl under some conditions.

Yeah, I have a bunch of legacy code and I'd imagine having to wade through this nightmare if we wanted to start to get some unit testing of any kind. Even trying to old "just add unit tests for the new code" isn't straightforward with a library swap.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Rocko Bonaparte posted:

I'll accept some clever linking as a way around macro hell. Although:

Yeah, I have a bunch of legacy code and I'd imagine having to wade through this nightmare if we wanted to start to get some unit testing of any kind. Even trying to old "just add unit tests for the new code" isn't straightforward with a library swap.

Shave parts of the main application off into libraries. Test the libraries.

Not sure why this is sounding more annoying here than in any other language? Is the hangup managing the build rules?

LLSix
Jan 20, 2010

The real power behind countless overlords

Rocko Bonaparte posted:

Has anybody seen and tried some strategies for getting mocks into unit tests for C code? Not C++, but C. I can't really imagine doing it thoroughly without devolving into some kind of macro hell. But who knows, maybe there's some compiler-specific moon beams or something.

Use the same headers but different definitions in different files. What we do is link in the mock files only in in the unit test compile.

e.g.

Foo.h

foo(int bah);

foo.c //real file
#include "foo.h"

foo(int bah
{
blah
}

bar.c //real file
#include "foo.h"

bar(int z)
{
foo(z);
...
}

//make file for product
... foo.c
bar.c

foo_mock.c //mock for testing
#include "foo.h"

foo(int bah
{
different blah
}

//make file for unit testing
... foo_mock.c
bar.c

Obviously this only works if you are compiling individual files in your unit test compile and not the entire library.

Admittedly, it took me most of a year to feel comfortable enough with the code base to do this, but it seems to be holding for the ~40% of the code base we've got covered now.

LLSix fucked around with this message at 19:04 on Mar 13, 2023

Volguus
Mar 3, 2009
I have a question about boost ASIO strand: Is a strand an executor or does it just have an executor? That is, if I make a ip::tcp::socket socket{strand} will then the async_receive/async_send be guaranteed to be executed serially?

I saw some stackoverflow posts that say it is an executor, but I didn't see anything in the official documentation saying so. My main use case here would be to not make a socket from an io_context but then to have to use bind_executor for the completion handler. The code would be that much simpler if I can just make the socket from the strand directly and then just use async_receive/async_write normally.

His Divine Shadow
Aug 7, 2000

I'm not a fascist. I'm a priest. Fascists dress up in black and tell people what to do.
I don't have a question but I just want to say the bitwise exercise in the C book I got is hard and makes me feel stupid. I had to go look at the solution and looked at alternative solutions and feel like I am barely hanging on. Hopefully I'll get there.

Subjunctive
Sep 12, 2006

✨sparkle and shine✨

His Divine Shadow posted:

I don't have a question but I just want to say the bitwise exercise in the C book I got is hard and makes me feel stupid. I had to go look at the solution and looked at alternative solutions and feel like I am barely hanging on. Hopefully I'll get there.

for bitwise stuff, I find it helpful to draw literal binary values on paper to model things out. can't juggle that poo poo in my head any more

His Divine Shadow
Aug 7, 2000

I'm not a fascist. I'm a priest. Fascists dress up in black and tell people what to do.
I have a function that writes it out on screen for me actually. Lifesaver. Though there might be some merit to writing on paper.

Volguus
Mar 3, 2009
The calculator in KDE (KCalc) has a "Show Bit Edit" mode. It's awesome.




It surely must be a feature in other calculators.

more falafel please
Feb 26, 2005

forums poster

Windows calculator (at least as of Windows 10) has a "programmer" mode that does a bunch of hex/octal/binary stuff.

Rottbott
Jul 27, 2006
DMC
The Windows calculator does that in Programmer mode.
Curses, beaten.

cheetah7071
Oct 20, 2010

honk honk
College Slice
When I'm doing bit stuff, I usually just think of it as an array of bools that you notate in a weird way, and will write out any constant I'm |ing or &ing with in 0b binary notation to emphasize which bits I'm using and make it more closely resemble logical operators than math operators.

more falafel please
Feb 26, 2005

forums poster

cheetah7071 posted:

When I'm doing bit stuff, I usually just think of it as an array of bools that you notate in a weird way, and will write out any constant I'm |ing or &ing with in 0b binary notation to emphasize which bits I'm using and make it more closely resemble logical operators than math operators.

Yeah, I've been doing bit-twiddling in some capacity off and on for 20+ years and I can't "see" the bits when a constant is written in hex (or worse, octal) still. 0b is great.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


Maybe I'm missing something, but why do you need to see anything? Suppose you have a definition like this:
code:
#define FLAG_P1 0x1
#define FLAG_P2 0x2
#define FLAG_P3 0x4
....
Then setting bits is just a matter of |ing together the appropriate flags, and testing for a property just requires that I & my storage with the flag for that property. No visualization is needed. Is my brain just broken from dealing with the old Win32 API?

dWord reserved

Rocko Bonaparte
Mar 12, 2002

Every day is Friday!
Let's say I have a pile of C kernel modules using the old init_module style that need to be changed to rename that to [insert_module_name_here]_init_module and then add module_init([insert_module_name_here]_init_module) in the same file. Is there some C refactoring tool where I could set that up for a hundred or so operations? I was figuring there must be something better than, say, bringing up ANTLR4 and writing a custom visitor or something. Just casually Googling was pretty disappointing, but it just might be that C++ is taking over that conversation that's a far harder language to reliably munge.

leper khan posted:

Shave parts of the main application off into libraries. Test the libraries.

Not sure why this is sounding more annoying here than in any other language? Is the hangup managing the build rules?

A lot of it is it's kernel level code hitting a lot of special functions that we'd have to somehow mock. So presumably we'd be replacing all those calls and kernel boilerplate with a localized equivalent in a different, userspace library.

I've been generally just trying to keep as much logic out of kernel-specific stuff. It's ... okayish for new code but it's not something I can readily do for a pile of legacy code unless I can do that initial refactor . . . without having any unit test coverage to prove I did it correctly.

The big reason I've been pretty pumped about Rust getting into the kernel is I think it would give me places where I can more easily switch out for mocks for testing kernel-level code.

cheetah7071
Oct 20, 2010

honk honk
College Slice

ultrafilter posted:

Maybe I'm missing something, but why do you need to see anything? Suppose you have a definition like this:
code:
#define FLAG_P1 0x1
#define FLAG_P2 0x2
#define FLAG_P3 0x4
....
Then setting bits is just a matter of |ing together the appropriate flags, and testing for a property just requires that I & my storage with the flag for that property. No visualization is needed. Is my brain just broken from dealing with the old Win32 API?

dWord reserved

I do basically this but it's just

C++ code:
constexpr uint8_t FLAG_1 0b00000001
constexpr uint8_t FLAG_2 0b00000010
which just works better with my brain. Idk. Maybe it doesn't for you. I also find it easier to follow if for some reason I need to work with multiple bits simultaneously. Like I have a file format where one of the bytes has 7 bits that represent a number from 0 to 127, and one bit which represents whether the data that follows is compressed or not. So my code for accessing the numeric portion is:

C++ code:
uint8_t PointFormat() const {
	constexpr std::uint8_t removeCompressedBit = 0b01111111;
	return ModifiedPointFormat & removeCompressedBit;
}
I could have called it 127 or 0x7F but 0b01111111 just makes it more clear to me at least what I'm actually doing here, to me.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

Rocko Bonaparte posted:

Let's say I have a pile of C kernel modules using the old init_module style that need to be changed to rename that to [insert_module_name_here]_init_module and then add module_init([insert_module_name_here]_init_module) in the same file. Is there some C refactoring tool where I could set that up for a hundred or so operations? I was figuring there must be something better than, say, bringing up ANTLR4 and writing a custom visitor or something. Just casually Googling was pretty disappointing, but it just might be that C++ is taking over that conversation that's a far harder language to reliably munge.

A lot of it is it's kernel level code hitting a lot of special functions that we'd have to somehow mock. So presumably we'd be replacing all those calls and kernel boilerplate with a localized equivalent in a different, userspace library.

I've been generally just trying to keep as much logic out of kernel-specific stuff. It's ... okayish for new code but it's not something I can readily do for a pile of legacy code unless I can do that initial refactor . . . without having any unit test coverage to prove I did it correctly.

The big reason I've been pretty pumped about Rust getting into the kernel is I think it would give me places where I can more easily switch out for mocks for testing kernel-level code.

For that sort of refactor I usually just rely on vim's bufdo and then review the output diff.

For testing the code, you just build it with a test harness that calls it and evaluates results.

more falafel please
Feb 26, 2005

forums poster

cheetah7071 posted:

I could have called it 127 or 0x7F but 0b01111111 just makes it more clear to me at least what I'm actually doing here, to me.

Exactly, I know intellectually that 127 and 7f are that same bit pattern, but I have to actually go through the step of Thinking About It, and my brain is terrible with things like off-by-ones (mostly, whether I should be correcting for an off-by-one or not). Any time I have to Think About It I increase the chance that I'll do it wrong. 0b01111111 makes it very clear that every bit except the MSB is set, so in the context of a mask, I can immediately see that that mask will give the same input with the MSB cleared.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


cheetah7071 posted:

Like I have a file format where one of the bytes has 7 bits that represent a number from 0 to 127, and one bit which represents whether the data that follows is compressed or not. So my code for accessing the numeric portion is:

C++ code:
uint8_t PointFormat() const {
	constexpr std::uint8_t removeCompressedBit = 0b01111111;
	return ModifiedPointFormat & removeCompressedBit;
}
I could have called it 127 or 0x7F but 0b01111111 just makes it more clear to me at least what I'm actually doing here, to me.

I'd write that as follows:
C++ code:
const uint8_t FLAG_COMPRESSED = 0x1 << 7;
const uint8_t MASK_NUMERIC_VALUE  = !FLAG_COMPRESSED;
Binary constants and anything more complicated than a power of 2 in hex is too much for me.

Rottbott
Jul 27, 2006
DMC
For flags I use enums (none of this 0x01, 0x02 stuff, just a normal enum class) along with a Flags<T> class which wraps a uint and provides a nice interface for flagsy operations. I prefer x[flag] = false; over x &= ~flag, but either style works. I've not run into any downsides with it yet except that it doesn't benefit from any built-in debugger flags visualisation.

Zopotantor
Feb 24, 2013

...und ist er drin dann lassen wir ihn niemals wieder raus...

ultrafilter posted:

I'd write that as follows:
C++ code:
const uint8_t FLAG_COMPRESSED = 0x1 << 7;
const uint8_t MASK_NUMERIC_VALUE  = !FLAG_COMPRESSED;
Binary constants and anything more complicated than a power of 2 in hex is too much for me.

Clearly. I think you'd want a tilde there.

ultrafilter
Aug 23, 2007

It's okay if you have any questions.


Would've been caught in tests.

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

Rottbott posted:

For flags I use enums (none of this 0x01, 0x02 stuff, just a normal enum class) along with a Flags<T> class which wraps a uint and provides a nice interface for flagsy operations. I prefer x[flag] = false; over x &= ~flag, but either style works. I've not run into any downsides with it yet except that it doesn't benefit from any built-in debugger flags visualisation.
Another downside is it's pretty hostile to any sort of serialization that treats the bytes-with-flags-in as bytes or ints or whatever, like old structs or various file formats.

His Divine Shadow
Aug 7, 2000

I'm not a fascist. I'm a priest. Fascists dress up in black and tell people what to do.
Well here's how I attempted to do exercise 2-7 in my C book. I have not looked at the answer yet but I feel pretty sure it's radically different, more compact. I do believe this code is pretty inefficient and can be optimized a lot and most of the x* variables can be removed but I wrote out it out like this to make it simpler to see and understand what's happening. The exercise is that I want to flip or invert any bits, starting at position p as well as n bits to the left of p. Leaving the rest unchanged.

My idea was to make two bit masks to mask of the area that is to be flipped, combine that into a new mask and then use said mask with a XOR operator on the original. I've tested it on a couple of numbers and it seems to work.





I noticed I have to use p-1 to start from bit 4 and not 5, which OK I can see that might work, it counts from 1 not 0 I guess. But then (p-1)+n doesn't yield the correct offset. There I have to remove the -1 . I'm still not sure why and I don't like it.

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

His Divine Shadow posted:

Well here's how I attempted to do exercise 2-7 in my C book. I have not looked at the answer yet but I feel pretty sure it's radically different, more compact. I do believe this code is pretty inefficient and can be optimized a lot and most of the x* variables can be removed but I wrote out it out like this to make it simpler to see and understand what's happening. The exercise is that I want to flip or invert any bits, starting at position p as well as n bits to the left of p. Leaving the rest unchanged.

My idea was to make two bit masks to mask of the area that is to be flipped, combine that into a new mask and then use said mask with a XOR operator on the original. I've tested it on a couple of numbers and it seems to work.





I noticed I have to use p-1 to start from bit 4 and not 5, which OK I can see that might work, it counts from 1 not 0 I guess. But then (p-1)+n doesn't yield the correct offset. There I have to remove the -1 . I'm still not sure why and I don't like it.

I would do something like

code:

uint32_t invert(uint32_t value, uint8_t position, uint8_t window_size) {
  uint32_t window_mask = ((1 << window_size) -1) << position;
  return value ^ window_mask;
}

Though there's likely something a bit more efficient in the bit twiddling hacks document.

Rottbott
Jul 27, 2006
DMC

roomforthetuna posted:

Another downside is it's pretty hostile to any sort of serialization that treats the bytes-with-flags-in as bytes or ints or whatever, like old structs or various file formats.

True, if you were wanting to just cast some bytes into Flags<T>, but it's easy to convert to/from the underlying int if you need it. I've my own serialisation system so Flags presents itself to that as just an int.

It's like any class which wraps a simple value to give it a nice interface, really. Say, a units library or a date-time class. Nobody would blink at using those so I don't know why more people don't do this with flags. It's really nice to use.

seiken
Feb 7, 2005

hah ha ha

ultrafilter posted:

Maybe I'm missing something, but why do you need to see anything? Suppose you have a definition like this:
code:
#define FLAG_P1 0x1
#define FLAG_P2 0x2
#define FLAG_P3 0x4
....
Then setting bits is just a matter of |ing together the appropriate flags, and testing for a property just requires that I & my storage with the flag for that property. No visualization is needed. Is my brain just broken from dealing with the old Win32 API?

dWord reserved

I agree that if all you're doing is setting and checking individual independent bits in a bitfield it's not really a problem, but that's the simplest application of bit twiddling. If you're doing something more involved then visualizing the bits can definitely be helpful. E.g. when dealing with custom serialization code or network serialization, custom numeric representations (like fixed-point) or other tricky low-level math stuff, that sort of thing.

His Divine Shadow
Aug 7, 2000

I'm not a fascist. I'm a priest. Fascists dress up in black and tell people what to do.

leper khan posted:

I would do something like

code:
uint32_t invert(uint32_t value, uint8_t position, uint8_t window_size) {
  uint32_t window_mask = ((1 << window_size) -1) << position;
  return value ^ window_mask;
}
Though there's likely something a bit more efficient in the bit twiddling hacks document.

Is there an advantage to doing it that way?

code:
 x2 = x ^ ((INT_MAX << (p - 1)) ^ (INT_MAX << (p+ n)));
I condensed my original to a single line anyway so I feel happy with it, unless it's terribly wrong somehow.

RPATDO_LAMD
Mar 22, 2013

🐘🪠🍆
readability?

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

His Divine Shadow posted:

Is there an advantage to doing it that way?

code:
 x2 = x ^ ((INT_MAX << (p - 1)) ^ (INT_MAX << (p+ n)));
I condensed my original to a single line anyway so I feel happy with it, unless it's terribly wrong somehow.

Fewer arithmetics. Readability. Real answer requires perf testing I'm too lazy to do right now for you :effort:

roomforthetuna
Mar 22, 2005

I don't need to know anything about virii! My CUSTOM PROGRAM keeps me protected! It's not like they'll try to come in through the Internet or something!

leper khan posted:

Fewer arithmetics. Readability. Real answer requires perf testing I'm too lazy to do right now for you :effort:
Almost guarantee that with optimizations on they will compile to the same thing.

Foxfire_
Nov 8, 2010

His Divine Shadow posted:

Is there an advantage to doing it that way?
Depends how your code golf contest is scored.

If they do compile to anything different, I'd guess it'd be from them doing different undefined behavior things on some inputs. A bunch of bitshift operations are undefined or implementation defined when applied to signed values when the shift amount is negative or bigger than the type being shifted.

Reminds me of a college assignment where we had a bunch of different functions to implement ("mirror this bit pattern" like you have, "count the number of set bits", ...) with per-function restricted sets of permitted operations and graded based on how many operations you used. Nothing you'd ever do in real code, but a reasonably entertaining way to teach bitwise stuff and edge case behavior.

Adbot
ADBOT LOVES YOU

leper khan
Dec 28, 2010
Honest to god thinks Half Life 2 is a bad game. But at least he likes Monster Hunter.

roomforthetuna posted:

Almost guarantee that with optimizations on they will compile to the same thing.

For modern compilers I wouldn't be surprised if that was true.

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