TIL: C++ character constants aren’t created equal

arrPtrTerm

When reviewing a patchset involving files, strings, timers, and multiple threads (essentially all the “tough to review” checkboxes right there), a comment from :froydnj caught my eye:

> +const char* kPersistenceFileName = "gv_measurements.json";
> +const char* kPersistenceFileNameNoExt = "gv_measurements";

Please make these `const char kPersistence...[] = "..."`, which is slightly smaller on all of our usual systems.

Why? Aren’t C arrays just pointers to the first element? Don’t we treat char[] and char* identically when logging or appending them to higher-order string objects?

Influenced by :Dexter and :jan-erik, I tried this out myself. I made two small C programs arr.c and ptr.c where the only difference was that one had a const char* and the other a const char[].

I compiled them both with gcc and then checked their sizes in bytes.arrPtrSizes

Sure enough, though ptr.c was smaller by one byte (* is one character and [] is two), after being compiled ptr was larger by a whole 8 bytes!

This is because C arrays aren’t identical to pointers to the first element. Instead they are identifiers that are (most of the time) implicitly converted to be pointers to the first element. For instance, if you’re calling a function void foo(char c[]), inside the function `c` is implicitly a char* and its size is that of a pointer, but outside of the function c could be an array with its size being the length of the array. As an example:

void foo(char c[]) {
  printf("sizeof(c): %d\n", sizeof c);
}
int main(void) {
  char arr[] = "a";
  printf("sizeof(arr): %d\n", sizeof arr);
  return 0;
}

Prints:

sizeof(arr): 2
sizeof(c): 8

Another way to think about this is that the char* form allocates two things: the actual string of four (“abc” plus “\0”) characters, and a pointer called ptr that contains the address of the place the ‘a’ character is stored.

This is in contrast to the char[] form which allocates just the four-character string and allows you to use the name arr to refer to the place the ‘a’ character is stored.

So, in conclusion, if you want to save yourself a pointer’s width on your constant strings, you may wish to declare them as char[] instead of char*.

:chutten

(( :glandium wrote a much deeper look at this problem if you’d like to see how much worse this can actually get thanks to relocations and symbol exporting ))

(( :bsmedberg wrote in to mention that you almost never want const char* for a constant anyway as the pointer isn’t const, only the data is. ))

Advertisements

TIL: Water Softeners

We wake up to hear an odd sound carried through the forced-air ducts. Furnace is loud, I think. My wife precedes me downstairs and, finding the sound louder, heads to the basement.

“Water in the basement!” comes her yell. I bound down the stairs two at a time and start shutting off water valves to stem the flow of a 3/4″ coldwater supply emptying through the water softener and onto the floor.

Water softeners are a piece of almost necessary equipment in the part of Canada where I live. Hard water is water that contains dissolved minerals (usually Calcium and Manganese) that, when present in sufficient amounts, can form “hard water scale.” This usually shows up on heating surfaces (the inside of kettles and water heaters) and on drying dishes (in the form of cloudy spots). Hard water’s not toxic or anything, but it’s a pain, and our water’s well into the category the USGS calls “very hard.” So we soften it.

Conventional water softeners work by exchanging those dissolved mineral ions (mostly Calcium around here) for salt ions (Sodium or Potassium) in tiny little resin beads kept in a column called the “resin tank” (or “mineral tank”) which you hook up to your water supply. The beads are made up of a compound to which salt binds less strongly than other ions (because it prefers ions missing two valence electrons, if you remember your High School Chemistry). Thus, when a bead with a bound salt is presented with a free-floating Calcium ion, the bead ditches the salt into the water and snatches up the Calcium.

The resulting water does not taste salty and does not meaningfully contribute to dietary salt intake, in case you were wondering.

Eventually these beads become full of these mineral ions. To return them to previous performance levels, they are soaked and flushed with a salt brine. Due to the brine’s high concentration of salt ions, the hardness ions leave the resins to form an equilibrium between the beads and the brine. Then the waste brine (now full of hardness ions as well as quite a lot of the salt) is sent down the drain.

To generate the brine, water is pumped into a salt storage tank (or “brine tank”) and then is left to dissolve salt. This salt is the only consumed quantity in this process, and must be regularly topped up (usually by purchasing 24kg bags of softener salt pellets at local grocery stores for under $6 a bag).

The whole recharge process takes about two hours.

Water softeners have an operating lifetime similar to that of the plumbing fittings you need to install it: ten to fifteen years.

Near as I can figure it, the water softener that decided to flood my basement was 14 years old when its resin tank decided to rupture catastrophically during a 2am recharge cycle. Two hours later, recharge cycle complete, it flipped the valve back to supply the house with soft water and then supplied itself with all of the house’s water.

Luckily my floor drain was nearby and could handle the water flow, so the only “damage” was a little splashed carpet in the next room and some garbage I’d been meaning to throw out. I’m not looking forward to the water bill next month, but I’m happy my furnace is installed on feet for just this sort of occasion.

I did get a nice close-up view of those tiny ion-exchange resin beads, though, as they had been spread all over the basement floor. They look like transparent cornmeal. When wet they kinda have the consistency of mashed potatoes.

One on-sale water softener from Canadian Tire and one plumber’s visit later, I’m once again living in the land of soft water. For the next ten to fifteen years.

So now I know rather more than I previously did about water softening. And so do you.

 

TIL: Feature Detection in Windows using GetProcAddress

In JavaScript, if you want to use a function that was introduced only in certain versions of browsers, you use Feature Detection. For example, you can ask “Hey, browser, do you have a function called `includes` on Array?” If the browser has it, you use it; and if it doesn’t, you either get along without it or load your own implementation.

It turns out that this same concept can be (and, in Firefox, is) done with Windows APIs.

Firefox for Windows is built against the Windows 10 SDK. This means the compiler knows the API calls and type definitions for all sorts of wondrous modern features like toast notifications and enumerating graphics adapters in a specific order.

However, as of writing, Firefox for Windows supports Windows 7 and up. What would happen if Firefox tried to use those fancy new Windows 10 features when running on Windows 7?

Well, at compile time (when Mozilla builds Firefox), it knows everything it needs to about the sizes and names of things used in the new features thanks to the SDK. At runtime (when a user runs Firefox), it needs to ask Windows at what address exactly all of those fancy new features live so that it can use them.

If Firefox can’t find a feature it expects to be there, it won’t start. We want Firefox to start, though, and we want to use the new features when available. So how do we both use the new feature (if it’s there) and not (if it’s not)?

Windows provides an API called GetProcAddress that allows the running program to perform some Feature Detection. It is asking Windows “Hey, so I’m looking for the address of this fancy new feature named FancyNewAPI. Do you know where that is?”. Windows will either reply “No, sorry” at which point you work around it, or “Yes, it’s over at address X” at which point to convert address X into a function pointer that takes the same number and types of arguments that the documentation said it takes and then instruct your program to jump into it and start executing.

We use this in Firefox to detect gamepad input modules, cancelable synchronous IO, display density measurements, and a whole bunch of graphics and media acceleration stuff.

And today (well, yesterday at this point) I learned about it. And now so have you.

:chutten

–edited to remove incorrect note that GetProcAddress started in WinXP– :aklotz noted that GetProcAddress has been around since ancient times, MSDN just periodically updates its “Minimum Supported Release” fields to drop older versions.