Saturday, August 16, 2025

Careful with AI tooling

AI tooling

 Since some period I started working with AI tooling. Mostly I use Gemini and Visual Studio's Copilot. The experience is a bit of mixed feelings about this. Gemini had some good suggestions but also failed many times. Copilot has good code completion suggestions but misses the mark also occasionally. Copilot's function name suggestions are very welcome.

 Some examples of AI tooling failing are listed here:

  • I asked Gemini for camera sharpness algorithm. It came up with a good algorithm but the actual OpenCV function calls and parameters were incorrect.
  • I asked Gemini to get the real sample time from an 'IMediaSample'. It hallucinated and suggested to use the non existing 'GetSampleTime'. There is a 'GetMediaTime' function but this returns the stream time; i.e. the time since the graph was running and not the time from the start of the video. 
  • I asked Gemini of conversion from UCS-2 to UTF-16. It wrongly suggested to use wstring_convert but wstring_covert is hardbound to std::string as byte_string
  • I asked Gemini for a natural sort algorithm. It came up with a good implementation and a clever trick to circumvent the conversion from string to integer numbers. It lacked though the removal of leading zero's which is essential for the clever trick to work.
  • I had to work on CMake lately but suggestions were often contradictory or using old conventions. In the CMake world things have shifted and perhaps the AI models are trained on old data.

 AI tooling can suggest plain bugs. I was implementing a swap of width and height and Copilot's code complete came up with the following code snippet:

// NOTE: incorrect 
Size sz = ...;
if (sz.GetWidth() < sz.GetHeight())
{
   sz.SetWidth(sz.GetHeight());
   sz.SetHeight(sz.GetWidth());
}

This doesn't swap but sets the width and height on the old height value.

 Conclusion

 AI tooling are helpful; mostly they give better answers than a Google search. It guided me lately through difficult CMake paths some very good answers but also ones who missed the boat. They are still not on the level to be trusted blindly. They also have limited scope for software engineering; e.g. code blocks; algorithms and functions. I am not aware if they can help in refactoring and extending architecture wide solutions.


Debugging GDI drawing

GDI debugging

 The other day I had to debug a hard to track drawing bug. The application is built with the MFC framework so it still uses GDI on places to draw custom controls.

 The incorrect drawing artifact was displayed after an invocation of 'DrawText' with the flag 'DT_CALCRECT'. This was unexpected since with the flag the function doesn't draw and only measures the size. Eventually I realized that GDI batches invocations so perhaps the buggy overdrawing had already taken place before. What was needed to prove this hypothesis:

  •  suppress GDI's caching mechanism through 'GdiSetBatchLimit'.
  •  use direct drawing; so no memory device context

 With this in place indeed it could be seen that the mistake happened earlier in the code and that the 'DrawText' invocation was merely a flush of the GDI batch.

 Be aware that suppressing  GDI's batch might not always work. When the window where the drawing took place was on the primary monitor the batch mode could be turned off but on the second monitor it still cached its calls.

Sunday, July 27, 2025

Watch out for an old VC++ runtime

 VC_redist.x64.exe

 For C/ C++ applications the VC++ runtime needs to be installed on the computer. The other day we experienced crashes when a component developed with a late version of VS2022 was crashing on a fresh installation of Windows 11. It turned out that this Windows 11 still uses an old version of the VC++ runtime which could crash the application (most notably in grabbing a std::mutex lock). After updating the PC with a recent version of 'VC_redist.x64.exe' the problem was solved.

 

Wednesday, July 23, 2025

ark.intel.com

 

Intel's website

 Intel had a wonderful website ark.intel.com where one could lookup the processor and its capabilities. For example information about capable instruction set (e.g. SSE 4.2; AVX; AVX2) was listed there. In a recent visit it was completely overhauled and they have removed (or hide) the possibility to lookup your processor with one click. 

 Great that Intel modernized their website but why destroy a valuable functionality?


Sunday, June 29, 2025

Watch out for atan change in Visual Studio 2022 17.14.6

atan

 Recently we updated Visual Studio 2022 17.14.6 and the regression test reported errors. It turned out that atan implementation was changed resulting a different value for debug vs release builts with CPU's having AVX2. One can recreate this with the following values:

    constexpr double ax        = 38.176459921094995;
    constexpr double ay        = 15.964755390006060;
    const double     dRotation = std::atan(ay/ax);

 We had to relax the equality checks; even for deterministic calculations.


Sunday, June 1, 2025

Careful with std::wfstream

wchar_t file streams

 The std::wfstream is similar to std::fstream except it accepts wchar_t. However it does not write std::wchar_t characters to file. Suppose the following code:

   std::wofstream ofs{L"c:\\temp\\1.txt" , std::ios_base::out | std::ios_base::binary};
   ofs.write(L"ABC", 3);

 On the Windows platform this writes just single bytes characters to the file. It uses the codecvt of the imbued locale which translated wchar_t to char. The standard C locale does not handle characters above the 255 so it will fail when using other characters than the extended ASCII character set. It will also fail when writing binary data through the write interface. It can be fixed by using a custom locale which leaves wchar_t unaffected. There was a codeproject article on this but it has been retracted.

 This translation is quite unexpected behavior since the function prototypes are defined in terms of wchar_t. It is also different compared to the wchar_t string streams: std::wstringstream does write wchar_t strings unaffected.

 This article was inspired by a YouTube comment of me where I stated that the C file stream API is less surprising. Of course there is always a clown who thinks better but probably doesn't know anything about above issue. With C stream I/O FILE and 'fwrite' the bytes are transferred to the file without interpretation and alteration.

FILE wrapper

 Jason Turner goes a lengthy way of wrapping the C file stream API but using a wrapper class would probably be simpler:

class c_file
{
public:
   c_file()
      : m_fp(nullptr)
   {
   }
   
   explicit c_file(const std::filesystem::path& rpth, const char* pszMode)
      : m_fp(fopen(rpth.string().c_str(), pszMode))
   {
   }

   ~c_file()
   {
      if (m_fp)
      {
         fclose(m_fp);
      }
   }

   c_file(const c_file&) = delete;

   c_file(c_file&& rOther) noexcept
      : m_fp(std::exchange(rOther.m_fp, nullptr))
   {
   }

   c_file& operator=(const c_file&) = delete;

   c_file& operator=(c_file&& rOther) noexcept
   {
      std::swap(m_fp, rOther.m_fp);
   }

   explicit operator bool() const
   {
      return m_fp;
   }

   size_t read(void* pBuffer, size_t size, size_t count)
   {
      return fread(pBuffer, size, count, m_fp);
   }

   size_t write(const void* pBuffer, size_t size, size_t count)
   {
      return fwrite(pBuffer, size, count, m_fp);
   }

   // etc.

private:
   FILE*    m_fp;
};

Links

Sunday, July 21, 2024

C++ horrible aspects

C++ horrible aspects

 Linus Torvalds described C++ as being a horrible language. Linus is not the best authority here since the dude has never programmed in C++ but the language has its dark corners. Still I would choose it any day over any other language. That also includes Linus favorite programming language C with its minimal feature set and security liabilities. 

Some questionable aspects in C++:

  • 'rvalue' references becoming 'lvalue' references. Not sure who invented this but he or she should be banned from the committee. It is super confusing that a reference type changes.
  • universal references and perfect forwarding. Again a very confusing idea to reuse the 'rvalue' reference syntax. The reference collapsing rules doesn't make it easier either. As some stated it was better to use a different syntax for perfect forwarding.
  • two phase lookup. this is a confusing rule which could have been circumvented by deferring template checking to instantiation time. The need to prefix template dependent types with 'typename' disappears. Making types and member functions (non) dependent is also not needed anymore since at instantiation time all type and context information is known to the compiler.
  • lack of uniformity in STL. For example there is reset and clear. Some algorithm's have _if variants when taking functors; others not.
  • functional programming style or object oriented. The regex functions are freestanding but why not make them member functions of regex? This prevents clutter of std namespace. It will probably also help Intellisense to build up its database which is very important these days in IDE's. 
  • uniform initialization. Again the committee made a mistake since constructors with initializer_list takes precedence over other constructors. This especially hurts the frequent used vector constructor which takes a size argument. The issue could be fixed by requiring double braces in case constructor invocation (e.g.std::vector<size_t>{{2}}). This is a slightly usability drawback but I prefer clarity over current situation.  
  • the ranges library has some strange aspects as well. Josuttis made a video about that.
  • trailing return types. Now there are various syntax's to return from a function. This could have been solved by allowing the return type be dependent on template arguments without the necessity to specify them afterwards.
  • concepts. One of the goal was to give clearer error messages. In practice they are as hard to decipher as in the old situation. On top of that the range library decided to use them as well which may result that something works with normal <algorithm> but with <ranges> one get a ton of compiler errors.
  • contracts. It's not voted yet in the language. It introduces a new syntax and rules different from C++. The assert macro in function body already fulfills a great deal of pre- and post condition checking in plain C++ which every programmer understands. If tool-ability is the main driver for contracts why not formalize them with e.g. recognizable names (e.g. pre_assert; post_assert). 

 Besides these aspects C++ misses out on an extended standard library. Compared to .NET or Java the C++ standard library is thin. One frequently need 3th party libraries (e.g. Boost) for basic things. This wouldn't be much of a problem if there was a standard package manger with de facto libraries like in Python. There it's a matter of just adding a library and you can start. This doesn't exist in C++ although there are package managers offered by certain companies (e.g. vcpkg). Getting the stuff build with CMake is another usability issue.

 Despite all these issues I still prefer C++ over any other programming language. One can decide to use what one is comfortable with and one needs. The exception mechanism is a topic of debate and many (embedded) environments choose not to use it. The constructor / destructor model is a very powerful aspect of C++ which alone gives the safety improvements over C through resource management and access wrappers. Generic programming and the STL is another major reason to prefer C++ over C.

 Linus is a technical gifted person but he hasn't a clue about C++. Some large applications and libraries (e.g. GCC; OpenCV) have made the transition and it improved a lot. OpenCV code base is cleaned up with the move to C++. The manual and clumsy CvMemStorage and CvSeq are not needed anymore in C++. The Linux kernel could have benefited from the extra facilities C++ offers but the dude is stubborn as hell.

Careful with refactoring

Refactoring issue  Last year we applied a small refactoring in a piece of code. The construct was a parent - child relationship with the chi...