共用方式為


Program Annotations

Notation is a favorite topic of mine being at least partly inspired by Bertrand Russell, who once wrote, “A good notation has a subtlety and suggestiveness which at times make it seem almost like a live teacher…and a perfect notation would be a substitute for thought.” An earlier post on notation deals with the linear format for mathematics used in Microsoft Office. The present post deals with annotations used to help code-proofing tools verify the correctness of computer programs, especially those written in C++.

The vast majority of programs in both Windows and Microsoft Office is written in C++. This choice benefits performance substantially, but C++ can act like a double-edged knife: you can cut with it, but it can cut you too! Accordingly people have written programs like Prefast that analyze programs for various kinds of errors, such as buffer overflows and null pointer dereferences, that cause crashes and security leaks. The analysis is greatly improved if annotations are included that define how the variables in the code are designed to be used. A great variety of annotations have been used over the years, but the current set, called SAL (source code annotation language) seems to be stabilizing and is used in both Office 2013 and Windows 8. This stabilization greatly aids development of programs like RichEdit, which are shipped in both environments.

While the benefits of SAL are great in improving program reliability, the annotations add substantial notational overhead that can slow down a programmer’s understanding of the code. The simple annotations like _In_ and _In_opt_ are easy enough to read and understand, but as the annotations have become more and more detailed, they have become increasingly opaque and unwieldy, such as _Out_opt_cap_post_count_(c, d) (don’t ask!). For example, this shows up in the RichEdit code base in the function header

 

HRESULT CMathFont::GetMathGlyphVariant (

       PCLSMATHSTYLE  pstyle,          // IN: Math style

       USHORT         gindex,                 // IN: Glyph index

       MATH_EXTENSION extType,      // IN: Extension type

       LONG           lDimension,             // IN: Measurement requested

       USHORT      cMaxComponent,   // IN: Maximum number of glyph components

       BOOL *         pfVariantFound,      // OUT: Returns true iff a variant is found

       USHORT *    pcComponents,       // OUT: # components in resulting construct

       _Out_opt_cap_post_count_(cMaxComponent, *pcComponents)

       USHORT *     piComponents,       // OUT: List of component glyph IDs

       _Out_opt_cap_post_count_(cMaxComponent, *pcComponents)

       LONG *         plOffsets)                 // OUT: List of glyph offsets

 

This function is used to get one or more glyphs used to display the input glyph at a particular size, such as a large integral sign. One can say that even without the _Out_opt_cap_post_count_(c, d) annotations this is a complicated function prototype, but with the annotations it’s particularly hard to read. And the function prototype is missing SAL annotations for the other argument variables (the comments explain the usage, but the code analysis tools don’t understand the comments).

While the annotations are included primarily for the code analysis tools, they do provide useful information for programmers if they can understand them and they should be available for inspection by programmers. Furthermore a programmer had to add them in the first place. They are not added automatically, although their absence is flagged by the code analysis tools.

So how can we get around this quandary of needing the annotations but not always wanting them staring us in the face? Two additions to the Visual Studio’s C++ editing environment would help: 1) tooltips that explain the annotations in plain English, and 2) the ability to suppress their display. Visual Studio has long been able to collapse/expand the bodies of if() statements. It could similarly provide the ability to collapse/expand the SAL annotations.

Comments

  • Anonymous
    February 20, 2013
    In the function header for CMathFont::GetMathGlyphVariant, should the last annotation be: Out_opt_cap_post_count(cMaxComponent, *piComponents) instead of: Out_opt_cap_post_count(cMaxComponent, *pcComponents)

  • Anonymous
    February 21, 2013
    The comment has been removed

  • Anonymous
    February 22, 2013
    The comment has been removed

  • Anonymous
    February 22, 2013
    The comment has been removed

  • Anonymous
    February 22, 2013
    Ah, I see what you mean. The way it was formatted made me think the code was: USHORT *pcComponents Out_opt_cap_post_count(cMaxComponent, *pcComponents), USHORT *piComponents Out_opt_cap_post_count(cMaxComponent, *pcComponents), LONG *plOffsets) As opposed to: USHORT *pcComponents, Out_opt_cap_post_count(cMaxComponent, *pcComponents) USHORT *piComponents, Out_opt_cap_post_count(cMaxComponent, *pcComponents) LONG *plOffsets)