Just a heads up to let you know that Axialis is offering an 82%-off discount on their Developer Suite V3 Bundle. I used some Axialis icons in past projects, and I really liked them.
Click this link and save now!
Just a heads up to let you know that Axialis is offering an 82%-off discount on their Developer Suite V3 Bundle. I used some Axialis icons in past projects, and I really liked them.
Click this link and save now!
Linus Torvalds criticized a RISC-V Linux kernel contribution from a Google engineer as “garbage code.” The discussion focuses on the helper function make_u32_from_two_u16() versus Linus’s proposed explicit code. Let’s discuss the importance of using proper type casting, bit manipulation, and creating a safer, reusable macro or function for clarity and bug reduction.
Recently, Linus Torvalds publicly dismissed a RISC-V code contribution to the Linux kernel made by a Google engineer as “garbage code”:
https://lkml.org/lkml/2025/8/9/76
First, I think Linus should be more respectful of other people.
In addition, let’s focus on the make_u32_from_two_u16() helper. My understanding is that this is a C preprocessor macro (as the Linux Kernel is mainly written in C). Let’s compare that helper with the explicit code “(a << 16) + b” proposed by Linus.
First, this explicit code is likely wrong, and in fact Linus adds that “maybe you need to add a cast”.
Why should we add a cast? In Linus’s words: “[…] to make sure that ‘b’ doesn’t have high bits that pollutes the end result”. So, what should the explicit code look like according to him? “(a << 16) + (uint16_t)b”?
But let’s do a step back. We should ask ourselves: What are the types of ‘a’ and ‘b’? From the helper’s name, I would think they are two “u16”, so two uint16_t.
If I was asked to write C code that takes two uint16_t values ‘a’ and ‘b’ as input and combines them into a uint32_t, I would write something like that:
((uint32_t)a << 16) | (uint32_t)b
I would use the bitwise OR (|) instead of +; I find it more appropriate as we are working at the bit manipulation level here. But maybe that’s just a matter of personal preference and coding style.
Moreover, I’d use the type casts as shown above, on both ‘a’ and ‘b’.
I’m not sure what Linus meant with ‘b’ potentially having “high bits that pollutes the end result”. Could ‘b’ be a uint32_t? In that case, I would use a bitmask like 0xFFFF with bitwise AND (&) to clear the high bits of ‘b’.
Moreover, I’d probably use better names for ‘a’ and ‘b’, too, like ‘high’ and ‘low’, to make it clear what is the high 16-bit word and what is the low 16-bit word.
So, the correct explicit code is not something as simple as “(a << 16) + b”. You may need to type cast, and you have to pay attention to do it correctly with proper use of parentheses. And you may potentially need to clear the high bits of ‘b’ with a bitmask?
And, if this operation of combining two uint16_t into a uint32_t is done in several places, you sure have many opportunities to introduce bugs with the explicit code that Linus advocates for in his email!
So, it would be much better, clearer, nicer, and safer, to raise the semantic level of the code, and write a helper function or macro to do that combination safely and correctly.
A C macro could look like this:
#include <stdint.h>
#define MAKE_U32_FROM_TWO_U16(high, low) \
( ((uint32_t)(high) << 16) | (uint32_t)(low) )
Should we take into consideration the case in which ‘low’ has higher bits to clear? Then the macro becomes something like this:
#define MAKE_U32_FROM_TWO_U16(high, low) \
( ((uint32_t)(high) << 16) | ((uint32_t)(low) & 0xFFFF))
As you can see, the type casts, the parentheses, the potential bit-masking, do require attention. But once you get the code right, you can safely and conveniently reuse it every time you need!
So, the real garbage code is actually repeatedly writing explicit bug-prone or wrong code, like “(a << 16) + b”! Not hiding such code in a sane helper macro (or function), like shown above.
Instead of a preprocessor macro, we could use an inline helper function. For example, in C++ we could write something like this:
#include <stdint.h>
inline uint32_t make_u32_from_two_u16(uint16_t high, uint16_t low)
{
return (static_cast<uint32_t>(high) << 16) |
static_cast<uint32_t>(low);
}
We could even further refine this function, marking it noexcept, as it’s guaranteed to not throw exceptions.
And we could also make the function constexpr, as it can be evaluated at compile-time when the input arguments are constant.
With these additional refinements, we get:
inline constexpr uint32_t make_u32_from_two_u16(
uint16_t high,
uint16_t low) noexcept
{
return (static_cast<uint32_t>(high) << 16) |
static_cast<uint32_t>(low);
}
Manually editing the tasks.json to add the desired C++ compiler option.
So, after the previous discussion on that confusing UI design choice, how can you set the C++ language standard version for building your C++ code in VS Code with the MS C/C++ Extension?
One option is to open the tasks.json file, and edit it to add the desired compiler option. In particular, to enable C++20 compilation mode, the option for the MSVC compiler is /std:c++20. So, add this option as a string “/std:c++20” in the args property array in tasks.json:

I still think that this modification to tasks.json should have been automatically done by the C/C++ Configurations UI, once the C++20 language standard version is set in there.
In VS Code, selecting the C++ language standard is not as intuitive as one would expect.
I have been using Visual Studio for C++ development since it was still called Visual C++ (and was a 100% C++-focused IDE), starting from version 4 (maybe 4.2) on Windows 95. I loved VC++ 6. Even today, Microsoft Visual Studio is still my first choice for C++ development on Windows.
In addition to that, I wanted to use VS Code for C++ development for some course work. Why choosing VS Code? Well, in addition to being free to use (as is the Visual Studio Community Edition), another important point of VS Code in that teaching context is its cross-platform feature: in fact, it’s available not only for Windows, but also for Linux and Mac, and students using those platforms could easily follow along.
I had VS Code and the MS C/C++ extension already installed on one of my PCs. I wrote some C++ demo code that used some C++20 features. I tried to build that code, and I got some error messages, telling me that I was using features that required at least C++20. Fine, I thought: Maybe the default C++ standard is set to something pre-C++20 (for example, VS 2019 defaults to C++14).
So, I pressed Ctrl+Shift+P, selected C/C++ Edit Configurations (UI), and in the C/C++ Configurations page, selected c++20 for the C++ standard.
Then I pressed F5 to start a debugging session, preceded by a build process, and saw that the build process failed.
I took a look at the error message in the terminal window, and to my surprise the error messages were telling me that some libraries (like <span>) were available only with C++20 or later. But I had just selected the C++20 standard a few minutes ago!
So, I double-checked, pressing Ctrl+Shift+P and selecting C/C++ Edit Configurations (UI), and in the C/C++ Configurations, the selected C++ standard was c++20, as expected.

I also took a look at the c_cpp_properties.json, and found that the “cppStandard” property was properly set to “c++20”, as well.

Despite these confirmations in the UI, I noted that in the terminal window, on the command line used to build the C++ source code, the option to set the C++20 compilation mode was not passed to the C++ compiler!

So, basically, the UI was telling me that the C++20 mode was enabled. But the C++ compiler was invoked in a way that did not reflect that, as the flag enabling C++20 was not specified on the command line!
I also tried to close and reopen VS Code, double-checked things one more time, but the results were always the same: C++20 was set in the C/C++ Configurations UI and in the c_cpp_properties.json file, but compilation failed due to the C++20 option not specified on the command line when invoking the C++ compiler.
I thought that this was a bug, and opened an issue on the MS C/C++ Extension GitHub page.
After some time, to my surprise, I noted that the issue was closed as “by design”! Seriously? I mean, what kind of good reasonable intuitive design is the one in which the UI tells you that you have selected a given C++ language standard, but the command line doesn’t compile your code according to that??
This is the comment associated to the closing of the issue:
This is “by design”. The settings in c_cpp_properties.json do not affect the build. You need to set the flags in your tasks.json or other source of build info (CMakeLists.txt etc.).
So, am I supposed to manually set the C++20 flag in the tasks.json, despite having already set it in the C/C++ Configurations UI? Well, I do think that is either a bug, or a bad and confusing design choice. If I set the C++20 option in the UI, that should be automatically reflected on the command line, as well. If a modification is required to tasks.json to enable C++20, that should have been the job of the UI, in which I had already selected the C++20 standard!
Compare that to the sane intuitive behavior of Visual Studio, in which you can simply set the C++ standard option in the UI, and the IDE will invoke the C++ compiler with the proper flags, reflecting that.

Let’s discuss a possible way to build a “bridge” between the managed C# world and the native C++ world, using P/Invoke.
Someone had a native C++ DLL, that exported a C-interface function. This exported function expected a const pointer to a custom structure, defined like this:
// Structure expected by the C++ native DLL
struct DllData
{
GUID Id;
int Value;
const wchar_t* Name;
};
The declaration of the function exported from the C++ DLL looks like this:
extern "C" HRESULT
__stdcall MyCppDll_ProcessData(const DllData* pData);
The request was to create a custom structure in C# corresponding to the DLL structure shown above, and pass an instance of that struct to the C-interface function exported by the C++ DLL.
In general, to pass data between managed C# code and native C++ code, there are several options available. For example:
The COM option is the most complex one, but probably also the most versatile. It would also allow reusing the wrapped C++ components from other programming languages that know how to talk with COM.
C++/CLI is an interesting option, easier than COM. However, like COM, it’s a Windows-only option. For example, considering this GitHub issue on .NET Core: C++/CLI migration to .Net core on Linux, it seems that C++/CLI is not supported on other platforms like Linux.
On the other hand, the P/Invoke option is available cross-platform on both Windows and Linux.
In the remaining part of this article, I’ll focus on the P/Invoke option to solve the problem at hand.
To be able to pass the custom structure from C# to the C++ DLL exported-function, we need two steps:
Let’s start with the step #1. This is the C++ structure:
// Structure expected by the C++ native DLL
struct DllData
{
GUID Id;
int Value;
const wchar_t* Name;
};
It contains three fields, of types: GUID, int, and const wchar_t*. We can map those in C# using the managed types Guid, Int32, and String. So, the corresponding C# structure definition looks like this:
[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]
public struct DllData
{
public Guid Id;
public Int32 Value;
public String Name;
}
Note that the CharSet field is set to CharSet.Unicode, to specify that the String fields should be copied from their managed C# format (which is Unicode UTF-16) to the native Unicode format (again, UTF-16 const wchar_t* in the C++ structure definition).
Now let’s focus on the step #2, which is the use of the DllImport attribute to import in C# the C-interface function exported by the native DLL. The native C-interface function has the following declaration:
extern "C" HRESULT
__stdcall MyCppDll_ProcessData(const DllData* pData);
I crafted the following P/Invoke C# declaration for it:
[DllImport("MyCppDll.dll",
EntryPoint = "MyCppDll_ProcessData",
CallingConvention = CallingConvention.StdCall,
ExactSpelling = true,
PreserveSig = false)]
static extern void ProcessData([In] ref DllData data);
The first parameter is the name of the native DLL: MyCppDll.dll in our case.
Then, I used the EntryPoint field to specify the name of the C-interface function exported from the DLL.
Next, I used the CallingConvention field to specify the StdCall calling convention, which corresponds to the C/C++ __stdcall.
With ExactSpelling=true we tell P/Invoke to search only for the function having the exact name we specified (MyCppDll_ProcessData in this case). Platform Invoke will fail if it cannot locate the function with that exact spelling.
Moreover, with the PreserveSig field set to false, we tell P/Invoke that the native function returns an HRESULT, and in case of error return codes, these will be automatically converted to exceptions in C#.
Finally, since the DllData structure is passed by pointer, I used a ref parameter in the C# P/Invoke declaration. In addition, since the pointer is marked const in C/C++, to explicitly convey the input-only nature of the parameter, I used the [In] attribute in the C# P/Invoke code.
Note that to use the above P/Invoke services, you need the System and System.Runtime.InteropServices namespaces.

Once you have set the above P/Invoke infrastructure, you can simply pass instances of the C# structure to the native C-interface function exported by the native C++ DLL, like this:
// Create an instance of the custom struct in C#
DllData data = new DllData
{
Id = Guid.NewGuid(),
Value = 10,
Name = "Connie"
};
// Pass it to the C++ DLL
ProcessData(ref data);
Piece of cake 😉
P.S. I uploaded some related compilable demo code here on GitHub.
Let’s see how to fix a common problem when building mixed C++/C# projects in Visual Studio.
Someone had a Visual Studio 2019 solution containing a C# application project and a native C++ DLL project. The C# application was supposed to call some C-interface functions exported by the native C++ DLL.
Both projects built successfully in Visual Studio. But, after the C# application was launched, a System.DllNotFoundException was thrown when the C# code tried to invoke the DLL-exported functions:

So, it looks like the C# application is unable to find the native C++ DLL.
In a first attempt to solve this problem, I tried manually copying the native C++ DLL from the folder where it was built into the same folder where the C# application was built (for example: from MySolution\Debug to MySolution\CSharpApp\bin\Debug). Then, I relaunched the C# application, and everything worked fine as expected this time! Wow 🙂 The problem was kind of easy to fix.
However, I was not 100% happy, as this was kind of a manual fix, that required manually copying-and-pasting the DLL from its own folder to the C# application folder. I would love to have Visual Studio doing that automatically!
Well, it turns out that we can do better than that! In fact, it’s possible to automate that process and basically instruct Visual Studio’s build system to perform the aforementioned copy for us. To do so, we basically need to specify a custom command line that VS automatically executes as a post-build event.
In Solution Explorer, right-click on the C# application project, and select Properties from the menu.
Select the Build Events tab, and enter the desired copy instruction in the Post-build event command line box. For example, the following command can be used:
xcopy "$(SolutionDir)$(Configuration)\MyCppDll.dll" "$(TargetDir)" /Y
Then type Ctrl+S or click the Save button (= diskette icon) in the toolbar to save these changes.

Basically, with the above settings we are telling Visual Studio: “Dear VS, after successfully building the C# application, please copy the C++ DLL from its original folder into the same folder where you have just built the C# application. Thank you very much!”
After relaunching the C# application, this time everything went well, and the C# EXE was able to find the C++ DLL and call its exported C-interface functions.
If you take a look at the custom copy command added in post-build event, you’ll notice some apparently weird syntax like $(SolutionDir) or $(TargetDir). These $(something) are basically MSBuild macros, that expand to meaningful stuff like the path of the Visual Studio solution, or the directory of the primary output file for the build (e.g. the directory where the C# application .exe file is created).
You can read more about those MSBuild macros in this MSDN page: Common macros for MSBuild commands and properties.
Note that the macros representing paths can include the trailing backslash \; for example, this is the case of $(SolutionDir). So, take that into account when combining these macros to refer to actual sub-directories and paths in your solution.
Considering the command used above:
xcopy "$(SolutionDir)$(Configuration)\MyCppDll.dll" "$(TargetDir)" /Y
$(SolutionDir) represents the full path of the Visual Studio solution, e.g. C:\Users\Gio\source\repos\MySolution\.
$(TargetDir) is the directory of the primary output file for the build, for example the directory where the C# console app .exe is created. This could be something like C:\Users\Gio\source\repos\MySolution\CSharpApp\bin\Debug\.
$(Configuration) is the name of the current project configuration, for example: Debug when doing a debug build.
So, for example: $(SolutionDir)$(Configuration) would expand to something like C:\Users\Gio\source\repos\MySolution\Debug in debug builds.
In addition, you can also see how these MSBuild macros are actually expanded in a given context. To do so in Visual Studio, once you are in the Build Events tab, click the Edit Post-build button. Then click the Macros > > button to view the actual expansions of those macros.

Let’s bust a myth that is a source of many subtle bugs. Are you sure that you can simply drop UTF-8-encoded text in char-based strings that expect ASCII text, and your C++ code will still work fine?
Several (many?) C++ programmers think that we should use UTF-8 everywhere as the Unicode encoding in our C++ code, stating that UTF-8 is a simple easy drop-in replacement for existing code that uses ASCII char-based strings, like const char* or std::string variables and parameters.
Of course, that UTF-8-simple-drop-in-replacement-for-ASCII thing is wrong and just a myth!
In fact, suppose that you wrote a C++ function whose purpose is to convert a std::string to lower case. For example:
// Code proposed by CppReference:
// https://en.cppreference.com/w/cpp/string/byte/tolower
//
// This code is basically the same found on StackOverflow here:
// https://stackoverflow.com/q/313970
// https://stackoverflow.com/a/313990 (<-- most voted answer)
std::string str_tolower(std::string s)
{
std::transform(s.begin(), s.end(), s.begin(),
// wrong code ...
// <omitted>
[](unsigned char c){ return std::tolower(c); } // correct
);
return s;
}
Well, that function works correctly for pure ASCII characters. But as soon as you try to pass it a UTF-8-encoded string, that code will not work correctly anymore! That was already discussed in my previous blog post, and also in this post on The Old New Thing blog.
I’ll give you another simple example. Consider the following C++ function, PrintUnderlined(), that receives a std::string (passed by const&) as input, and prints it with an underline below:
// Print the input text string, with an underline below
void PrintUnderlined(const std::string& text)
{
std::cout << text << '\n';
std::cout << std::string(text.length(), '-') << '\n';
}
For example, invoking PrintUnderlined(“Hello C++ World!”), you’ll get the following output:
Hello C++ World!
----------------
Well, as you can see, this function works fine with ASCII text. But, what happens if you pass UTF-8-encoded text to it?
Well, it may work as expected in some cases, but not in others. For example, what happens if the input string contains non-pure-ASCII characters, like the LATIN SMALL LETTER E WITH GRAVE è (U+00E8)? Well, in this case the UTF-8 encoding for “è” is represented by two bytes: 0xC3 0xA8. So, from the viewpoint of the std::string::length() method, that “single character è” counts as two chars. So, you’ll get two underscore characters for the single è, instead of the expected one underscore character. And that will produce a bogus output with the PrintUnderlined function! And note that this same function works correctly for ASCII char-based strings.
So, if you have some existing C++ code that works with const char* or std::string, or similar char-based string types, and assumes ASCII encoding for text, don’t expect to pass a UTF-8-encoded strings and have it just automagically working fine! The existing code may still compile fine, but there is a good chance that you could have introduced subtle runtime bugs and logic errors!

Spend some time thinking about the exact type of encoding of the const char* and std::string variables and parameters in your C++ code base: Are they pure ASCII strings? Are these char-based strings encoded in some particular ANSI/Windows code pages? Which code page? Maybe it’s an “ANSI” Windows code page like Latin 1 / Western European Windows-1252 code page? Or some other code page?
You can pack many different kinds of stuff in char-based strings (ASCII text, text encoded in various code pages, etc.), and there is no guarantee that code that used to work fine with that particular encoding would automatically continue to work correctly when you pass UTF-8-encoded text.
If we could start everything from scratch today, using UTF-8 for everything would certainly be an option. But, there is a thing called legacy code. And you cannot simply assume that you can just drop UTF-8-encoded strings in the existing char-based strings in existing legacy C++ code bases, and that everything will magically work fine. It may compile fine, but running fine as expected is another completely different thing.
Use STL string objects like std::string/std::wstring as a safe bridge.
Last time, we saw that passing a C++ std::[w]string_view to a C-interface API (like Win32 APIs) expecting a C-style null-terminated string pointer can cause subtle bugs, as there is a requirement impedance mismatch. In fact:
So, supposing that you have a C++17 (or newer) code base that heavily uses string views, when you need to interface those with Win32 API function calls, or whatever C-interface API, expecting C-style null-terminated strings, how can you safely pass instances of string views as input parameter?
Invoking the string_view/wstring_view’s data method would be dangerous and source of subtle bugs, as the data returned pointer is not guaranteed to point to a null-terminated string.
Instead, you can use a std::string/wstring object as a bridge between the string views and the C-interface API. In fact, the std::string/wstring’s c_str method does guarantee that the returned pointer points to a null-terminated string. So it’s safe to pass the pointer returned by std::[w]string::c_str to a C-interface API function that expects a null-terminated C-style string pointer (like PCWSTR/LPCWSTR parameters in the Win32 realm).
For example:
// sv is a std::wstring_view
// C++ STL strings can be easily initialized from string views
std::wstring str{ sv };
// Pass the intermediate wstring object to a Win32 API,
// or whatever C-interface API expecting
// a C-style *null-terminated* string pointer.
DoSomething(
// PCWSTR/LPCWSTR/const wchar_t* parameter
str.c_str(), // wstring::c_str
// Other parameters ...
);
// Or use a temporary string object to wrap the string view
// at the call site:
DoSomething(
// PCWSTR/LPCWSTR/const wchar_t* parameter
std::wstring{ sv }.c_str(),
// Other parameters ...
);
Passing STL std::[w]string objects at Win32 API boundaries is common for C++ code that calls into Win32 C-interface APIs. When is it safe to pass *string views* instead?
A common question I have been asked many times goes along these lines: “I need to pass a C++ string as input parameter to a Windows Win32 C API function. In modern C++ code, should I pass an STL string or a string view?”
Let’s start with some refinements and clarifications.
First, assuming the Windows C++ code is built in Unicode UTF-16 mode (which has been the default since Visual Studio 2005), the STL string class would be std::wstring, and the corresponding “string view” would be std::wstring_view.
Moreover, since wstring objects are, in general, not cheap to copy, I would consider passing them via const&. Use reference (&) to avoid potentially expensive copies, and use const, since these string parameters are input parameters, and they will not be modified by the called function.
So, the two competing options are typically:
// Use std::wstring passed by const&
SomeReturnType DoSomething(
/* [in] */ const std::wstring& s,
/* other parameters */
)
{
// Call some Win32 API passing s
...
}
// Use std::wstring_view (passing by value is just fine)
SomeReturnType DoSomething(
/* [in] */ std::wstring_view sv,
/* other parameters */
)
{
// Call some Win32 API passing sv
...
}
So, which form should you pick?
Well, that’s a good question!
In general, I would say that if the Win32 API you are wrapping/calling takes a pointer to a null-terminated C-style string (i.e. a const wchar_t*/PCWSTR/LPCWSTR parameter), then you should pick std::wstring.
An example of that is the SetWindowText Windows API. Its prototype is like this:
// In Unicode builds, SetWindowText expands to SetWindowTextW
BOOL SetWindowTextW(
HWND hWnd,
LPCWSTR lpString
);
When you write some code like this:
SetWindowText(hWndName, L"Connie"); // Unicode build
the SetWindowText(W) API is expecting a null-terminated C-style string. If you pass a std::wstring object, like this:
std::wstring name = L"Connie";
SetWindowText(hWndName, name.c_str()); // Works fine!
the code will work fine. In fact, the wstring::c_str() method is guaranteed to return a null-terminated C-style string pointer.
On the other hand, if you pass a string view like std::wstring_view in that context, you’ll likely get some subtle bugs!
To learn more about that, you may want to read my article: The Case of string_view and the Magic String.
Try experimenting with the above API and something like “Connie is learning C++” and string views!

On the other hand, there are Win32 APIs that accept also a pointer to some string characters and a length. An example of that is the LCMapStringEx API:
int LCMapStringEx(
LPCWSTR lpLocaleName,
DWORD dwMapFlags,
LPCWSTR lpSrcStr, // <-- pointer
int cchSrc, // <-- length (optional)
/* ... other parameters */
);
As it can be read from the official Microsoft documentation about the 4th parameter cchSrc, this represents (emphasis mine):
“(the) Size, in characters, of the source string indicated by lpSrcStr. The size of the source string can include the terminating null character, but does not have to.
(…) The application can set this parameter to any negative value to specify that the source string is null-terminated.”
In other words, the aforementioned LCMapStringEx API has two “input” working modes with regard to this aspect of the input string:
If you use the API in working mode #1, explicitly passing a size value for the input string, the input string is not required to be null-terminated!
In this case, you can simply use a std::wstring_view, as there is no requirement for null-termination for the input string. And a std::[w]string_view is basically a pointer (to string characters) + a size.
Of course, you can still use the “classic” C++ option of passing std::wstring by const& in this case, as well. But, you also have the other option to safely use wstring_view.