Ruminations
type: channel
description: Mulling over topics I find interesting
date: 2024-02-22T13:35:00Z
update period: hourly
update frequency: 1
update base: 2000-01-01T12:00+00:00
generator agent: https://wordpress.org/
items: Musings on the C charter
items: What’s New in C in 2023?
items: Don’t use the likely or unlikely attributes
items: Member Function Ref Qualifiers
items: Binary Operator Overloading
items: Implementing a four-bit adder with C++ template metaprogramming
items: Interesting Note About the sizeof Operator
items: MSVC Pointer Type Attributes
items: Small Break in the Silence
items: How Variable Argument Lists Work in C

Musings on the C charter
type: item
creator: Aaron Ballman
date: 2023-12-29T14:52:11Z
subject: C/C++
subject: c
subject: ISO
description: Within the C committee, there’s been a lot of talk about what the C charter means and whether it should be updated or not. My personal musing on the topic is that the C charter needs to be updated in … Continue reading →
encoded: Within the C committee, there’s been a lot of talk about what the C charter means and whether it should be updated or not. My personal musing on the topic is that the C charter needs to be updated in order for C to remain relevant long-term. Whether C should remain relevant long-term is an exercise left to the reader. Note, these thoughts may change over time as I gather more feedback from more places. Existing code is important, existing implementations are not. A standard is a treaty between implementor and programmer. Migration of an existing code base is an issue. Minimize incompatibilities with C90. I think we could combine these principles into one bullet instead of four because they’re all effectively about code migration to newer standard versions. Each new release of C should provide a simple upgrade path from the previous release of C so that users can gradually transition between adjacent versions of C, but incompatibilities between releases are acceptable. In other words, it’s fine to deprecate old functionality even without replacement, or remove previously deprecated functionality (again, even without replacement), but this should only be done with significant justification given the costs to users of C. Changing the standard a code base compiles against is a new agreement between the programmer and the implementer; it is akin to changing your code (as is changing your compiler), and there should be no expectation that everything remains identical to how it was before. Older functionality will be deprecated, newer functionality will be added, bugs will be fixed, etc. New standard == new treaty. I think we should be careful about blind adherence to this principle. It’s obviously true that there’s a lot of economic value tied up in existing C code bases and that rewriting that code is both expensive and error-prone. However, C has undergone multiple revisions in its long history. A good idea in 1978 is not necessarily even acceptable practice in 2024. I …

What’s New in C in 2023?
type: item
creator: Aaron Ballman
date: 2023-10-01T18:11:59Z
subject: C/C++
subject: c
subject: c23
description: The year is 2023 and you’re asking “What’s new in C?” Surely the answer is “absolutely nothing”, right? Wrong! C23 will be released in the coming months (likely in early 2024), and this is a whirlwind tour of what changes … Continue reading →
encoded: The year is 2023 and you’re asking “What’s new in C?” Surely the answer is “absolutely nothing”, right? Wrong! C23 will be released in the coming months (likely in early 2024), and this is a whirlwind tour of what changes were made for the latest revision of one of the world’s most popular programming languages. I originally prepared this talk for NDC Tech Town in Kongsberg, but I was unable to give the talk because a hurricane + poor airline services interrupted my travel plans. Oh well, their loss is your gain! I hope you enjoy the talk. Errata The slide about underlying enumeration types did not make it clear that the choice of the underlying type for the enumeration type is implementation-defined, so the given types in the comments might be incorrect depending on your implementation. When mentioning that signed overflow is still implementation-defined, I misspoke. I was talking about this situation involving unsigned -> signed conversion: unsigned int i = UINT_MAX; signed int j = i; // Implementation-defined behavior However, signed *overflow* is still undefined behavior, as it always was. e.g., signed int i = INT_MAX + 1; // Undefined behavior

Don’t use the likely or unlikely attributes
type: item
creator: Aaron Ballman
date: 2020-08-27T14:57:39Z
subject: C/C++
subject: attributes
subject: C++20
description: C++20 introduced the likelihood attributes likely and unlikely as a way for a programmer to give an optimization hint to their implementation that a given code path is more or less likely to be taken. On its face, this seems … Continue reading →
encoded: C++20 introduced the likelihood attributes likely and unlikely as a way for a programmer to give an optimization hint to their implementation that a given code path is more or less likely to be taken. On its face, this seems like a great set of attributes because you can give hints to the optimizer in a way that is hopefully understood by all implementations and will result in faster performance. What’s not to love? The attribute is specified to appertain to arbitrary statements or labels with the recommended practice “to optimize for the case where paths of execution including it are arbitrarily more likely|unlikely than any alternative path of execution that does not include such an attribute on a statement or label.” Pop quiz, what does this code do? if (something) { likely; unlikely; foo(something); } Sorry, but the answer key for this quiz is currently unavailable. However, one rule you should follow about how to use these attributes is: never allow both attributes to appear in the same path of execution. Lest you think, “but who would write such bad code?”, consider this reasonable-looking-but-probably-very-unfortunate code: #define MY_COOL_ASSERT(x) unlikely assert(x) if (something) { likely; MY_COOL_ASSERT(something > 0); foo(something); } Despite the name, these attributes do not mark whether the statement itself is likely, only whether the path leading to the statement is likely. This brings us to our second rule: only mark the dominating statement or label of the flow control path you want to optimize for. This will often mean you only mark the compound statement after a flow control statement, as in: if (foo) likely { do_something(foo); } while (bar) unlikely { ; } switch (baz) { likely case 0: whatever(); break; unlikely case 1: something_else(); break; default: break; } Speaking of code that looks reasonable when you apply the attribute to the dominating statement of flow control, what does this code do? if (foo)…

Member Function Ref Qualifiers
type: item
creator: Aaron Ballman
date: 2014-07-08T14:05:02Z
subject: C/C++
subject: C++0x
subject: member functions
subject: qualifiers
description: One of the lesser-known features of C++11 is the fact that you can overload your non-static member functions based on whether the implicit this object parameter is an lvalue reference or an rvalue reference by specifying a functions ref-qualifier. This … Continue reading →
encoded: One of the lesser-known features of C++11 is the fact that you can overload your non-static member functions based on whether the implicit this object parameter is an lvalue reference or an rvalue reference by specifying a functions ref-qualifier. This feature works similar to the way cv-qualifiers work when specifying a method must be called on a const or volatile object, and can in fact be combined with cv-qualifiers. To specify a ref-qualifier for a member function, you can either qualify the function with & or &&. (The ref-qualifier must come after any cv-qualifiers.) For instance, if you wanted to declare a function to be called on an rvalue reference object only, you would write: struct S { void func() &&; }; S s1; s1.func(); // Ill-formed S().func(); // OK If you want to overload a function based on the rvalue-ness of the implicit object parameter, you must specify the ref-qualifier for both functions. struct S { void func() &; void func() &&; }; S s1; s1.func(); // OK, calls S::func() & S().func(); // OK, calls S::func() && Overloading based on a ref-qualifier is useful in (somewhat rare) circumstances where your object can make use of move semantics to reduce expensive construction costs. For instance: #include <iostream> #include <utility> class ExpensiveState {}; // Details unimportant class Builder { ExpensiveState State; public: Builder() = default; Builder(const Builder &O) : State(O.State) { std::cout << "Copy" << std::endl; } Builder(Builder &&O) : State(std::move(O.State)) { std::cout << "Move" << std::endl; } Builder operator()() & { return Builder(*this); } Builder operator()() && { return Builder(std::move(*this)); } }; int main() { Builder b; b()()()(); } When executed, this code will output: Copy Move Move Move. The Copy is because b is an lvalue, not an rvalue, and so operator()() & will be called. However, the results of that function are an rvalue, and so the subsequent subexpressions will result in calling operator()() &&. Due to this, reso…

Binary Operator Overloading
type: item
creator: Aaron Ballman
date: 2014-06-23T14:38:32Z
subject: C/C++
subject: Framework Design
subject: friend
subject: operators
description: In C++, there are two forms of binary operator overloading you can use when designing an API. The first form is to overload the operator as a member function of the class, and the second form is to overload the … Continue reading →
encoded: In C++, there are two forms of binary operator overloading you can use when designing an API. The first form is to overload the operator as a member function of the class, and the second form is to overload the operator as a friend function of the class. I want to explore why you would use one form of overloading instead of the other, using a Fraction class as an example. For the purposes of this discussion, this is part of the interface for our expository class. class Fraction { // Implementation details live here. public: Fraction(int Whole); Fraction(int Numerator, unsigned Demoninator); Fraction(double Value); // Binary operator overloads live here. }; One of the ways we can implement our binary operator overloads is as member functions of the Fraction class. I’m going to pick on the equality operator, but any of the overloaded binary operators would suffice. ... // Binary operator overloads live here. bool operator==(const Fraction &RHS) const; ... The other way we can implement our binary operator overloads is as a friend function of the Fraction class. ... // Binary operator overloads live here. friend bool operator==(const Fraction &LHS, const Fraction &RHS); Since there are two different ways to implement this, it’s reasonable to ask which way is “correct?” The answer to that question depends on your intentions as a class designer. Consider the following use case: void f(const Fraction &F) { if (1.0 == F) { // Do something interesting } } Some coding conventions suggest that equality comparisons against a constant value put the constant on the left-hand side of the comparison (so that an accidental assignment operation by typing = instead of == would trigger a compile error), so this example is not particularly far-fetched. If you use a member function for the operator overload, this code would not compile because there’s no way for the implicit converting constructor from double to Fraction to be called. However, by using a friend function for the operator…

Implementing a four-bit adder with C++ template metaprogramming
type: item
creator: Aaron Ballman
date: 2013-11-14T18:53:17Z
subject: C/C++
subject: templates
description: I recently read a post by Phillip Larkson where the C preprocessor was used to implement a four-bit adder entirely at compile time. This got me wondering whether I could implement the same concept using C++ template metaprogramming. It seemed … Continue reading →
encoded: I recently read a post by Phillip Larkson where the C preprocessor was used to implement a four-bit adder entirely at compile time. This got me wondering whether I could implement the same concept using C++ template metaprogramming. It seemed theoretically possible as all the components can be calculated at runtime, but I wanted to avoid making use of the preprocessor for anything but supplying the original values to be added. The goal was to compile something on the command line like: clang -DNUMBER_1=5 -DNUMBER_2=7 foo.cpp and have the value 12 written out to the command line. It turns out that this is relatively straight-forward to implement in C++. You can encode the bitwise operators AND and XOR with template specializations, and the remainder of the adder is bookkeeping for the sum and carry bits. The bitwise operators and adder themselves look like: struct one_bit { static const unsigned value = 1; }; struct zero_bit { static const unsigned value = 0; }; template <unsigned A1, unsigned B1> struct and_op : public zero_bit {}; template <> struct and_op<1, 1> : public one_bit{}; template <unsigned A1, unsigned B1> struct xor_op : public zero_bit {}; template <> struct xor_op<1, 0> : public one_bit{}; template <> struct xor_op<0, 1> : public one_bit{}; template <unsigned A1, unsigned B1, unsigned cin> struct full_adder { static const unsigned sum = xor_op<xor_op<A1, B1>::value, cin>::value; static const unsigned carry = xor_op<and_op<xor_op<A1, B1>::value, cin>::value, and_op<A1, B1>::value>::value; }; I define a pair of base structures to represent a zero bit and a one bit. The base operator is not specialized, and results in the zero bit. The specializations for the operators return the one bit for the correct operands. The full_addr structure implements the typical sum and carry operations which are described on Wikipedia. As I mentioned, implementing the four-bit adder is a matter of bookkeeping for the bits, and so I made a helper structures called two_bit_a…

Interesting Note About the sizeof Operator
type: item
creator: Aaron Ballman
date: 2013-06-21T16:03:17Z
subject: C/C++
subject: sizeof
subject: unexpected behavior
description: The expression used in a sizeof operator is an unevaluated expression in C and C++. This can make for some surprising situations if you are unaware of it. For instance: #include <stdio.h> int main( void ) { int a = … Continue reading →
encoded: The expression used in a sizeof operator is an unevaluated expression in C and C++. This can make for some surprising situations if you are unaware of it. For instance: #include <stdio.h> int main( void ) { int a = 12; int b = sizeof( ++a ); printf( "%d\n", a ); return 0; } This code will print 12 instead of 13 because the expression ++a is unevaluated. So what does it mean for an expression to be unevaluated? Basically, it means that the expression is used at compile time only as a way to determine a type, which is then used to evaluate the result of the sizeof operator. So in the above example, a’s type is determined, and the resulting type for ++ is determined, but no code is generated to execute the ++. Here’s an abusive example that demonstrates this: #include <stdio.h> class c { public: double operator++(); }; int main(int argc, char *argv[]){ c c1; int i = sizeof( ++c1 ); int j = sizeof( c1 ); ::printf( "%d, %d\n", i, j ); return 0; } If you run this code, you will see 8, 1 printed and will not get a link error (because of the failure to define operator++)!

MSVC Pointer Type Attributes
type: item
creator: Aaron Ballman
date: 2013-05-15T15:49:37Z
subject: C/C++
subject: Win32
description: One of the lesser-known features of Visual Studio’s C/C++ compiler are the pointer type attributes __ptr32 and __ptr64. More information about them can be found on MSDN. These pointer type attributes are used to control the visible size and behavior … Continue reading →
encoded: One of the lesser-known features of Visual Studio’s C/C++ compiler are the pointer type attributes __ptr32 and __ptr64. More information about them can be found on MSDN. These pointer type attributes are used to control the visible size and behavior of pointers in 32- and 64-bit applications. Their usage is a bit strange, but if you need to do interop between 32- and 64-bit mode, they can be handy features to have. Additionally, there are the __sptr and __uptr qualifiers which allow you to specify how the pointer types are extended. __sptr denotes sign extension, and __uptr denotes zero extension. Information about these qualifiers can also be found on MSDN. The behavior of these type attributes is strange, to say the least. I wanted to take a moment to document what I’ve observed the behavior to be, as of Visual Studio 2012. For starters, the documentation is a bit misleading for __ptr32 and __ptr64. Specifically, the documentation states: On a 32-bit system, a pointer declared with __ptr64 is truncated to a 32-bit pointer. On a 64-bit system, a pointer declared with __ptr32 is coerced to a 64-bit pointer. However, this isn’t strictly accurate. When you use a type with a specific pointer size, the returned pointer will be sized accordingly regardless of architecture you are targeting. For instance, if you use __ptr64 on an x86 build, you will get a 64-bit pointer value. If you pass it to functions, use it in structures, call sizeof on it, etc, it will occupy 8 bytes of space, even though you are on a 32-bit system. However, when you dereference the pointer, it will only use the low 32-bits of the pointer. For instance: #include <stdlib.h> void func( int * __ptr64 p ) { *p = 12; } int main( void ) { int * __ptr64 p = (int * __ptr64)::malloc( sizeof( int * __ptr64 ) ); func( p ); return 0; } If you compile this code and take a look at the resulting disassembly, you will notice some interesting behaviors: mov esi, esp ; sizeof( int * __ptr64 ) yields 8 push 8 ; call m…

Small Break in the Silence
type: item
creator: Aaron Ballman
date: 2012-08-14T13:05:39Z
subject: Uncategorized
description: Just because I’ve not written many posts lately doesn’t mean I’ve been silent. You should go check out the Tidbits page, it currently has over 20 little juicy pieces of information about C and C++. I’ve been using it as … Continue reading →
encoded: Just because I’ve not written many posts lately doesn’t mean I’ve been silent. You should go check out the Tidbits page, it currently has over 20 little juicy pieces of information about C and C++. I’ve been using it as a training exercise for my coworkers, and it’s been very successful so far. I’ll likely be continuing with regular Friday updates of Tidbits for quite a while to come. I do hope to write some more full-length blog posts now that life is starting to settle back down again. So I’m not dormant, honest!

How Variable Argument Lists Work in C
type: item
creator: Aaron Ballman
date: 2012-06-20T20:24:25Z
subject: C/C++
subject: calling conventions
subject: functions
subject: varargs
subject: x86
description: Variable argument lists are very arcane in the world of C. You’ll see them expressed in function signatures as … at the end of the parameter list, but you may not understand how they work or what they do. There … Continue reading →
encoded: Variable argument lists are very arcane in the world of C. You’ll see them expressed in function signatures as … at the end of the parameter list, but you may not understand how they work or what they do. There are two sides to every function at runtime: the caller and the callee, and they both need to agree on the semantics of how the function call works (how do parameters get passed, return values returned, etc). The caller’s side is pretty easy with variable arguments because the compiler will continue to pass parameters like it normally would, right up until the terminating parenthesis. For the caller, it’s no different than any other function call except for the fact that the compiler will allow any number of arguments (including zero) after the initial parameters. They all get pushed onto the stack (depending on architecture and calling conventions) in the proper order, and the callee is responsible for figuring them out. The callee side, on the other hand, is quite interesting. Let’s take a look at a typical function: void foo( int bar, ... ) { va_list args; va_start( args, bar ); for (;;) { some_type t = va_arg( args, some_type ); /* Do something with t */ } va_end( args ); } The way it works on the callee side is that you must use the “va” functions: va_start, va_arg and va_end as a way to query for the parameter list. The first thing you’ll notice is the only way to call va_start is by passing in the last parameter in the list (the parameter preceding the …). This is because the only way for variable argument lists to work is for the callee to know where the function parameters live, and you can only do that if you have at least one formal parameter. Because va_start needs the exact location of the parameter, it is a macro instead of a function — this allows it to get at the address of the parameter on the correct stack. Once you’ve gotten the start of the va_list, you get each individual argument by using the va_arg macro. This macro takes the list as wel…