Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c++ > #67243 > unrolled thread

An example: code to list exports of a Windows DLL.

Started by"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
First post2019-08-02 03:36 +0200
Last post2019-08-20 17:24 -0700
Articles 20 on this page of 34 — 11 participants

Back to article view | Back to comp.lang.c++


Contents

  An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-02 03:36 +0200
    Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-02 11:22 +0200
    Re: An example: code to list exports of a Windows DLL. rick.c.hodgin@gmail.com - 2019-08-02 02:33 -0700
      Re: An example: code to list exports of a Windows DLL. "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-02 16:54 -0700
        Re: An example: code to list exports of a Windows DLL. "Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com> - 2019-08-02 19:09 -0700
    Now on Github; based ordinals in listing (Re: An example: code to list exports of a Windows DLL.) "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-02 20:20 +0200
    Re: An example: code to list exports of a Windows DLL. legalize+jeeves@mail.xmission.com (Richard) - 2019-08-19 19:44 +0000
      Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-20 02:12 +0200
        Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-19 18:31 -0700
          Re: An example: code to list exports of a Windows DLL. David Brown <david.brown@hesbynett.no> - 2019-08-20 08:42 +0200
            Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-20 02:18 -0700
              Re: An example: code to list exports of a Windows DLL. Ian Collins <ian-news@hotmail.com> - 2019-08-20 22:22 +1200
                Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-20 14:21 -0700
              Re: An example: code to list exports of a Windows DLL. David Brown <david.brown@hesbynett.no> - 2019-08-20 13:00 +0200
                Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-20 14:59 -0700
                  Re: An example: code to list exports of a Windows DLL. David Brown <david.brown@hesbynett.no> - 2019-08-21 10:29 +0200
                    Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-21 11:14 +0200
                      Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-21 02:55 -0700
                        Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-21 12:30 +0200
                          Re: An example: code to list exports of a Windows DLL. David Brown <david.brown@hesbynett.no> - 2019-08-21 14:22 +0200
                          Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-21 12:41 -0700
                            Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-22 03:38 +0200
                              Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-21 19:24 -0700
                                Re: An example: code to list exports of a Windows DLL. James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-08-21 23:21 -0400
                                Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-22 06:01 +0200
                                  Re: An example: code to list exports of a Windows DLL. James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-08-22 00:26 -0400
                                    Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-22 07:54 +0200
                                      Re: An example: code to list exports of a Windows DLL. James Kuyper <jameskuyper@alumni.caltech.edu> - 2019-08-22 09:08 -0400
                                        Re: An example: code to list exports of a Windows DLL. "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> - 2019-08-22 19:37 +0200
                              Re: An example: code to list exports of a Windows DLL. scott@slp53.sl.home (Scott Lurndal) - 2019-08-22 13:17 +0000
                                Re: An example: code to list exports of a Windows DLL. David Brown <david.brown@hesbynett.no> - 2019-08-22 16:07 +0200
                    Re: An example: code to list exports of a Windows DLL. Keith Thompson <kst-u@mib.org> - 2019-08-21 02:42 -0700
    Re: An example: code to list exports of a Windows DLL. Frederick Gotham <cauldwell.thomas@gmail.com> - 2019-08-20 04:09 -0700
      Re: An example: code to list exports of a Windows DLL. "Chris M. Thomasson" <chris.m.thomasson.1@gmail.com> - 2019-08-20 17:24 -0700

Page 1 of 2  [1] 2  Next page →


#67243 — An example: code to list exports of a Windows DLL.

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-08-02 03:36 +0200
SubjectAn example: code to list exports of a Windows DLL.
Message-ID<qi042o$if8$1@dont-email.me>
This just-now-it-compiled-and-appeared-to-work code is for whoever needs 
or desires a tool to list DLL exports (e.g. because of the large amount 
of irrelevant output from MS `dumpbin`, or because one doesn't want to 
install Visual Studio but instead just use MinGW g++), or those 
interested in the internal structure of a Windows PE format executable.

For the latter, if it's still available on the web then one could do 
worse than reading Matt Pietrek's two- or three part article series.

I once posted an exports listing program like this on Stack Overflow, 
back then only for 32-bit DLLS, and as I recall then by loading the DLL 
and using the pointers in the image directly as pointers. This code 
instead reads the file. As I recall from the SO posting the function 
names are stored internally with UTF-8 encoding, but the documentation 
says ASCII, yet, on the third hand, the documentation of encodings used 
in Windows is known to be wildly inaccurate & misleading. I've yet to 
test that. But apparently the documentation of `GetProcAddr` (the 
Windows way of getting a pointer to specified function in a loaded DLL) 
now says ASCII, instead of previously Windows ANSI.

The $ things in the following code are macros from the specified 
header-only library on GitHub. E.g. `$use_std` expands to a `using` 
declaration that prepends `std::` to each specified name. If use of the 
library is undesired then just manually expand the macro invocations.

The "winapi-header-wrappers" micro-library is not on GitHub or anywhere, 
but they're just simple wrappers, mostly just ensuring that 
`<windows.h>` is included, because MS headers are not self-sufficient.


------------------------------------------------------------------------
#include <cppx-core/all.hpp>                        // <url: 
https://github.com/alf-p-steinbach/cppx-core>
#include <winapi-header-wrappers/windows-h.hpp>     // Just a 
<windows.h> wrapper with UNICODE defined.
#include <winapi-header-wrappers/shellapi-h.hpp>    // CommandLineToArgvW

namespace win_util {
     $use_std( exchange );
     $use_cppx( Wide_c_str, Mutable_wide_c_str, hopefully, P_ );

     class Command_line_args
     {
         P_<Mutable_wide_c_str>      m_parts;
         int                         m_n_parts;

         Command_line_args( const Command_line_args& ) = delete;
         auto operator=( const Command_line_args& ) -> 
Command_line_args& = delete;

     public:
         auto count() const -> int                           { return 
m_n_parts - 1; }
         auto operator[]( const int i ) const -> Wide_c_str  { return 
m_parts[i + 1]; }
         auto invocation() const -> Wide_c_str               { return 
m_parts[0]; }

         Command_line_args():
             m_parts( CommandLineToArgvW( GetCommandLine(), &m_n_parts ) )
         {
             hopefully( m_parts != nullptr )
                 or $fail( "CommandLineToArgvW failed" );
         }

         Command_line_args( Command_line_args&& other ):
             m_parts( exchange( other.m_parts, nullptr ) ),
             m_n_parts( exchange( other.m_n_parts, 0 ) )
         {}

         ~Command_line_args()
         {
             if( m_parts != nullptr ) {
                 LocalFree(  m_parts );
             }
         }
     };

}  // namespace win_util

namespace app {
     $use_std(
         cout, clog, endl, invoke, runtime_error, string, vector
         );
     $use_cppx(
         hopefully, fail_, Is_zero,
         Byte, fs_util::C_file, Size, Index, C_str,
         fs_util::read, fs_util::read_, fs_util::read_sequence, 
fs_util::read_sequence_,
         fs_util::peek_,
         is_in, P_, to_hex, up_to
         );
     namespace fs = std::filesystem;
     using namespace cppx::basic_string_building;        // operator<<, 
operator""s

     // A class to serve simple failure messages to the user, via 
exceptions. These
     // exceptions are thrown without origin info, and are presented as 
just strings.
     // Don't do this in any commercial code.
     class Ui_exception:
         public runtime_error
     { using runtime_error::runtime_error; };

     using Uix = Ui_exception;

     struct Pe32_types
     {
         using Optional_header = IMAGE_OPTIONAL_HEADER32;
         static constexpr int address_width = 32;
     };

     struct Pe64_types
     {
         using Optional_header = IMAGE_OPTIONAL_HEADER64;
         static constexpr int address_width = 64;
     };

     template< class Type >
     auto from_bytes_( const P_<const Byte> p_first )
         -> Type
     {
         Type result;
         memcpy( &result, p_first, sizeof( Type ) );
         return result;
     }

     template< class Type >
     auto sequence_from_bytes_( const P_<const Byte> p_first, const Size n )
         -> vector<Type>
     {
         vector<Type> result;
         if( n <= 0 ) {
             return result;
         }

         result.reserve( n );
         for( const Index i: up_to( n ) ) {
             result.push_back( from_bytes_<Type>( p_first + i*sizeof( 
Type ) ) );
         }
         return result;
     }

     // When this function is called the file position is at start of 
the optional header.
     template< class Pe_types >
     void list_exports(
         const string&               u8_path,
         const C_file&               f,
         const IMAGE_FILE_HEADER&    pe_header
         )
     {
         cout << Pe_types::address_width << "-bit DLL." << endl;

         using Optional_header = typename Pe_types::Optional_header;
         const auto pe_header_opt = read_<Optional_header>( f );

         hopefully( IMAGE_DIRECTORY_ENTRY_EXPORT < 
pe_header_opt.NumberOfRvaAndSizes )
             or fail_<Uix>( ""s << "No exports found in '" << u8_path << 
"'." );

         const auto section_headers = invoke( [&]()
             -> vector<IMAGE_SECTION_HEADER>
         {
             vector<IMAGE_SECTION_HEADER> headers;
             for( int _: up_to( pe_header.NumberOfSections ) ) {
                 (void) _;  headers.push_back( 
read_<IMAGE_SECTION_HEADER>( f ) );
             }
             return headers;
         } );

         const auto& dir_info = 
pe_header_opt.DataDirectory[IMAGE_DIRECTORY_ENTRY_EXPORT];

         hopefully( dir_info.Size >= sizeof( IMAGE_EXPORT_DIRECTORY ) )
             or fail_<Uix>( "Ungood file: claimed size of export dir 
header is too small." );

         const IMAGE_SECTION_HEADER& section = invoke( [&]()
         {
             const auto dir_addr         = dir_info.VirtualAddress;
             const auto beyond_dir_addr  = dir_addr + dir_info.Size;

             for( const auto& s: section_headers ) {
                 const auto s_addr           = s.VirtualAddress;
                 const auto beyond_s_addr    = s_addr + s.SizeOfRawData;

                 if( s_addr <= dir_addr and beyond_dir_addr <= 
beyond_s_addr ) {
                     return s;
                 }
             }
             fail_<Uix>( "Ungood file: no section (fully) contains the 
export table." );
         } );

         hopefully( section.SizeOfRawData > 0 )
             or fail_<Uix>( "Ungood file: section with export table, is 
of length zero." );

         const auto addr_to_pos      = section.PointerToRawData - 
section.VirtualAddress;
         const auto dir_position     = dir_info.VirtualAddress + 
addr_to_pos;
         fseek( f, dir_position, SEEK_SET ) >> Is_zero()
             or fail_<Uix>( "Ungood file: a seek to the exports table 
section failed." );
         const auto dir              = read_<IMAGE_EXPORT_DIRECTORY>( f );

         if( dir.NumberOfFunctions == 0 ) {
             cout << "No functions are exported";
         } else if( dir.NumberOfFunctions == 1 ) {
             cout << "1 function is exported, at ordinal 0";
         } else if( dir.NumberOfFunctions > 1 ) {
             cout    << dir.NumberOfFunctions << " functions are exported"
                     << ", at ordinals 0 ... " << dir.NumberOfFunctions - 1;
         }
         cout << "." << endl;

         if( dir.NumberOfFunctions == 0 ) {
             return;
         }

         fseek( f, dir.AddressOfNames + addr_to_pos, SEEK_SET ) >> Is_zero()
             or fail_<Uix>( "Ungood file: a seek to the name addresses 
table failed." );
         const vector<DWORD> name_positions = read_sequence_<DWORD>( f, 
dir.NumberOfNames );

         vector<string> names;
         names.reserve( name_positions.size() );
         for( const DWORD name_addr: name_positions ) {
             string name;
             int ch;
             fseek( f, name_addr + addr_to_pos, SEEK_SET ) >> Is_zero()
                 or fail_<Uix>( "Ungood file: a seek to the an export 
name failed." );
             while( (ch = fgetc( f )) != EOF and ch != 0 ) {
                 name += char( ch );
             }
             names.push_back( name );
         }

         fseek( f, dir.AddressOfNameOrdinals + addr_to_pos, SEEK_SET ) 
 >> Is_zero()
             or fail_<Uix>( "Ungood file: a seek to the ordinals table 
failed." );
         const vector<WORD> ordinals = read_sequence_<WORD>( f, 
dir.NumberOfNames );

         cout << string( 72, '-' ) << endl;
         for( const int i: up_to( dir.NumberOfNames ) ) {
             cout << names[i] << " @" << ordinals[i] << endl;
         }
     }

     void run()
     {
         const auto args             = win_util::Command_line_args();
         hopefully( args.count() == 1 )
             or fail_<Uix>( "Specify one argument: the DLL filename or 
path." );

         const fs::path dll_path     = args[0];
         const string u8_path = cppx::fs_util::utf8_from( dll_path );

         const auto f = C_file( tag::Read(), dll_path );

         const auto dos_header       = read_<IMAGE_DOS_HEADER >( f );
         hopefully( dos_header.e_magic == IMAGE_DOS_SIGNATURE ) 
//0x5A4D, 'MZ' multichar.
             or fail_<Uix>( ""s << "No MZ magic number at start of '" << 
u8_path << "'." );

         fseek( f, dos_header.e_lfanew, SEEK_SET ) >> Is_zero()
             or fail_<Uix>( "fseek to PE header failed" );

         const auto pe_signature     = read_<DWORD>( f );
         hopefully( pe_signature == IMAGE_NT_SIGNATURE  ) 
//0x4550, 'PE' multichar.
             or fail_<Uix>( ""s << "No PE magic number in PE header of 
'" << u8_path << "'." );

         const auto pe_header        = read_<IMAGE_FILE_HEADER>( f );
         const auto image_kind_spec  = peek_<WORD>( f );

         switch( image_kind_spec ) {
             case IMAGE_NT_OPTIONAL_HDR32_MAGIC: {               // 0x10B
                 list_exports<Pe32_types>( u8_path, f, pe_header );
                 break;
             }
             case IMAGE_NT_OPTIONAL_HDR64_MAGIC: {               // 0x20B
                 list_exports<Pe64_types>( u8_path, f, pe_header );
                 break;
             }
             default: {      // E.g. 0x107 a.k.a. 
IMAGE_ROM_OPTIONAL_HDR_MAGIC
                 fail_<Uix>( "Not a PE32 (32-bit) or PE32+ (64-bit) 
file." );
             }
         };
     }
}  // namespace app

auto main() -> int
{
     $use_std( exception, cerr, endl, clog, ios_base );
     $use_cppx( monospaced_bullet_block, description_lines_from );

     #ifdef NDEBUG
         clog.setstate( ios_base::failbit );     // Suppress trace output.
     #endif
     try {
         app::run();
         return EXIT_SUCCESS;
     } catch( const app::Ui_exception& x ) {
         cerr << "!" << x.what() << endl;
     } catch( const exception& x ) {
         cerr << monospaced_bullet_block( description_lines_from( x ) ) 
<< endl;
     }
     return EXIT_FAILURE;
}
------------------------------------------------------------------------


Example output:


[P:\commands\list-exports]
 > a "c:\windows\system32\user32.dll" | more
64-bit DLL.
1215 functions are exported, at ordinals 0 ... 1214.
------------------------------------------------------------------------
ActivateKeyboardLayout @3
AddClipboardFormatListener @4
AdjustWindowRect @5
AdjustWindowRectEx @6
AdjustWindowRectExForDpi @7
AlignRects @8
AllowForegroundActivation @9
AllowSetForegroundWindow @10
AnimateWindow @11
...


The missing ordinals, and there are many more later in the sequence, may 
be undocumented functions exported by ordinal only.



Cheers!,

- Alf

[toc] | [next] | [standalone]


#67248

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-08-02 11:22 +0200
Message-ID<qi0vd4$96q$1@dont-email.me>
In reply to#67243
I looked at the code again this morning and noticed a potential bug, of 
using unsigned types:

On 02.08.2019 03:36, Alf P. Steinbach wrote:
>          const auto addr_to_pos      = section.PointerToRawData - 
> section.VirtualAddress;
>          const auto dir_position     = dir_info.VirtualAddress + 
> addr_to_pos;

This uses unsigned types (Microsoft's choice) limited to 32 bits. And 
yes, the "pointer" and "virtual address" values in a DLL file are 32-bit 
even for a 64-bit DLL. Again, that's Microsoft's decision.

But when e.g. `addr_to_pos` is added to an address value that's 
represented with 64 bits (I don't think I do that, but /if/), then the 
offset will not act as negative, if it's in that direction. To prevent 
possible such mishaps the offset type above should be signed:

         const INT32 addr_to_pos     = section.PointerToRawData - 
section.VirtualAddress;
         const DWORD dir_position    = dir_info.VirtualAddress + 
addr_to_pos;

The lesson here is system independent: beware of unsigned arithmetic, 
don't use unsigned types for /numbers/, even when the API that one 
relates to, does that.


Cheers!,

- Alf

[toc] | [prev] | [next] | [standalone]


#67249

Fromrick.c.hodgin@gmail.com
Date2019-08-02 02:33 -0700
Message-ID<001f7da5-9bcc-4b91-a4a7-69f574cb2154@googlegroups.com>
In reply to#67243
On Thursday, August 1, 2019 at 9:36:34 PM UTC-4, Alf P. Steinbach wrote:
> This just-now-it-compiled-and-appeared-to-work code is for whoever needs 
> or desires a tool to list DLL exports (e.g. because of the large amount 
> of irrelevant output from MS `dumpbin`, or because one doesn't want to 
> install Visual Studio but instead just use MinGW g++), or those 
> interested in the internal structure of a Windows PE format executable.


If you do want to use Visual Studio and dumpbin, here's a great
tutorial video by a premiere WinDbg developer on DLLs:

    CppCon 2017:
    James McNellis
    “Everything You Ever Wanted to Know about DLLs”

    https://www.youtube.com/watch?v=JPQWQfDhICA&t=17m30s

-- 
Rick C. Hodgin

[toc] | [prev] | [next] | [standalone]


#67256

From"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>
Date2019-08-02 16:54 -0700
Message-ID<qi2if8$uuq$1@gioia.aioe.org>
In reply to#67249
On 8/2/2019 2:33 AM, rick.c.hodgin@gmail.com wrote:
> On Thursday, August 1, 2019 at 9:36:34 PM UTC-4, Alf P. Steinbach wrote:
>> This just-now-it-compiled-and-appeared-to-work code is for whoever needs
>> or desires a tool to list DLL exports (e.g. because of the large amount
>> of irrelevant output from MS `dumpbin`, or because one doesn't want to
>> install Visual Studio but instead just use MinGW g++), or those
>> interested in the internal structure of a Windows PE format executable.
> 
> 
> If you do want to use Visual Studio and dumpbin, here's a great
> tutorial video by a premiere WinDbg developer on DLLs:
> 
>      CppCon 2017:
>      James McNellis
>      “Everything You Ever Wanted to Know about DLLs”
> 
>      https://www.youtube.com/watch?v=JPQWQfDhICA&t=17m30s
> 

dumpbin is very nice. Btw, I am 99.999...% sure you are familiar with:

https://docs.microsoft.com/en-us/sysinternals

Always like this as well:

http://www.dependencywalker.com

;^)

[toc] | [prev] | [next] | [standalone]


#67258

From"Chris M. Thomasson" <invalid_chris_thomasson_invalid@invalid.com>
Date2019-08-02 19:09 -0700
Message-ID<qi2qdh$1ue5$1@gioia.aioe.org>
In reply to#67256
On 8/2/2019 4:54 PM, Chris M. Thomasson wrote:
> On 8/2/2019 2:33 AM, rick.c.hodgin@gmail.com wrote:
>> On Thursday, August 1, 2019 at 9:36:34 PM UTC-4, Alf P. Steinbach wrote:
[...]
> Always like this as well:
> 
> http://www.dependencywalker.com

Its been a while since I used this. Fun that it works on an Alpha.

[toc] | [prev] | [next] | [standalone]


#67254 — Now on Github; based ordinals in listing (Re: An example: code to list exports of a Windows DLL.)

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-08-02 20:20 +0200
SubjectNow on Github; based ordinals in listing (Re: An example: code to list exports of a Windows DLL.)
Message-ID<qi1uta$ncj$1@dont-email.me>
In reply to#67243
On 02.08.2019 03:36, Alf P. Steinbach wrote:
> This just-now-it-compiled-and-appeared-to-work code is for whoever needs 
> or desires a tool to list DLL exports (e.g. because of the large amount 
> of irrelevant output from MS `dumpbin`, or because one doesn't want to 
> install Visual Studio but instead just use MinGW g++), or those 
> interested in the internal structure of a Windows PE format executable.

[snip]

I added base adjustment of ordinals.

MS' `dumpbin` does that, GNU `objdump` doesn't but reports it elsewhere 
in its listing.

The code is now on GitHub with the 2 microlibraries used as submodules,

     <url: https://github.com/alf-p-steinbach/list-exports>

Cheers!,

- Alf

[toc] | [prev] | [next] | [standalone]


#67783

Fromlegalize+jeeves@mail.xmission.com (Richard)
Date2019-08-19 19:44 +0000
Message-ID<qjeu6n$gcq$1@news.xmission.com>
In reply to#67243
[Please do not mail me a copy of your followup]

"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
<qi042o$if8$1@dont-email.me> thusly:

>The $ things in the following code are macros from the specified 
>header-only library on GitHub.

Can you tell me where in the standard it allows for $ to be part of an
identifier?

I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
-- 
"The Direct3D Graphics Pipeline" free book <http://tinyurl.com/d3d-pipeline>
            The Terminals Wiki <http://terminals-wiki.org>
     The Computer Graphics Museum <http://computergraphicsmuseum.org>
  Legalize Adulthood! (my blog) <http://legalizeadulthood.wordpress.com>

[toc] | [prev] | [next] | [standalone]


#67792

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-08-20 02:12 +0200
Message-ID<qjfdtk$qgu$1@dont-email.me>
In reply to#67783
On 19.08.2019 21:44, Richard wrote:
> [Please do not mail me a copy of your followup]
> 
> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
> <qi042o$if8$1@dont-email.me> thusly:
> 
>> The $ things in the following code are macros from the specified
>> header-only library on GitHub.
> 
> Can you tell me where in the standard it allows for $ to be part of an
> identifier?
> 
> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.

In the future you might risk that people think you're a total novice, 
one who doesn't even know the basics of identifiers in C++.

Having called you out on that:

I've not yet heard of a practical problem with it with any compiler. 
However, when Herb Sutter tried this naming scheme on some years after I 
first did it, he got negative reactions from some people whose company 
used a critical custom preprocessing step where `$` was significant, and 
which was sufficiently simple-minded to be misled into doing the Wrong 
Thing™. So he dropped the scheme, but I don't have to. :)

No sane person would e.g. rewrite `#pragma once` to more verbose and 
ugly and error prone include guards with formally guaranteed behavior 
just to get that formal guarantee, but if there is a problem with the 
`$`s, like the aforementioned preprocessing, then you can replace these 
macro names with their uppercase aliases. Less readable IMO. But YMMV.


Cheers & hth.,

- Alf

[toc] | [prev] | [next] | [standalone]


#67794

FromKeith Thompson <kst-u@mib.org>
Date2019-08-19 18:31 -0700
Message-ID<ln1rxg4o6t.fsf@kst-u.example.com>
In reply to#67792
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
> On 19.08.2019 21:44, Richard wrote:
>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>> <qi042o$if8$1@dont-email.me> thusly:
>>
>>> The $ things in the following code are macros from the specified
>>> header-only library on GitHub.
>>
>> Can you tell me where in the standard it allows for $ to be part of an
>> identifier?
>>
>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>
> In the future you might risk that people think you're a total novice,
> one who doesn't even know the basics of identifiers in C++.

Then I'll risk the same thing.  Can you explain where C++17 permits $
in identifiers (or where it permits compilers to permit it)?

Earlier editions of the standard, such as C++11, permitted "other
implementation-defined characters" in identifiers.  This was dropped
after Defect Report #1963 pointed out that it was supposedly redundant.

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1963

In N4700 (a more recent C++17 draft), identifiers may contain the 52
upper and lower case letters, the 10 decimal digits, underscores, and
universal-character-names.  Characters not in the basic source character
set are mapped to universal-character-names in translation phase 1, so $
will (probably) be mapped to \u0024 .

But universal-character-names in identifiers are only allowed by
designate characters in certain ranges (Table 2 in 5.10 [lex.name]), and
\u0024 is not in any of those ranges.

For example, this program prints "42" when I compile and run it with
g++, but clang++ rejects it (it warns about the '$' in an identifier
and says that "foo" is undeclared on the "std::cout << ..." line).
(I used "-std=c++17 -pedantic" for both.)

#include <iostream>
int main() {
    const int foo$bar = 42;
    std::cout << foo\u0024bar << "\n";
}

I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
and therefore require a diagnostic from any conforming compiler (which
implies that gcc is non-conforming).

It's possible that it was intended to permit (but not require) support
for $ in identifiers, but that that was overlooked in the response to
Defect Report #1963.  Perhaps 0024 should be added to Table 2?

Or perhaps I'm missing something (always a real possibility).

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#67799

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-20 08:42 +0200
Message-ID<qjg4nq$u1t$1@dont-email.me>
In reply to#67794
On 20/08/2019 03:31, Keith Thompson wrote:
> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>> On 19.08.2019 21:44, Richard wrote:
>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>> <qi042o$if8$1@dont-email.me> thusly:
>>>
>>>> The $ things in the following code are macros from the specified
>>>> header-only library on GitHub.
>>>
>>> Can you tell me where in the standard it allows for $ to be part of an
>>> identifier?
>>>
>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>
>> In the future you might risk that people think you're a total novice,
>> one who doesn't even know the basics of identifiers in C++.
> 
> Then I'll risk the same thing.  Can you explain where C++17 permits $
> in identifiers (or where it permits compilers to permit it)?
> 

It doesn't.

> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
> and therefore require a diagnostic from any conforming compiler (which
> implies that gcc is non-conforming).
> 

You get the warning with "-Wpedantic" and an appropriate "-std" C++ 
standard (and perhaps an appropriate version of gcc).

> Or perhaps I'm missing something (always a real possibility).
> 

What you are missing is that $ is accepted in identifiers in many 
compilers, and Alf simply does not care that it is not supported in the 
standards as long as it is supported in the compilers he uses.

This is not an unreasonable attitude, if you like the kind of macro 
libraries he has (I don't personally, but some people do) and he is 
certainly not alone in it.  But I think it would be a better to be much 
clearer about it being non-standard.

Future directions of C++ are seriously considering adding $ for use in 
metadata (metaclasses, introspection, etc.), which may break his library 
or at least cause confusion.

And there are plenty of compilers that won't accept $ as an identifier 
letter (such as gcc for the AVR - a perfectly valid, if small and 
limited, C++ target), and others where it can cause trouble with 
assemblers which use $ as a comment symbol (68k) or in register names 
(many, including ARM).

As long as Alf's code is for his own use, and he only uses the compilers 
/he/ chooses, with the compiler flags /he/ chooses, then he is of course 
free to use $ in his identifiers.  But he should not expect others to be 
as happy with it.

[toc] | [prev] | [next] | [standalone]


#67802

FromKeith Thompson <kst-u@mib.org>
Date2019-08-20 02:18 -0700
Message-ID<lnwof82o0v.fsf@kst-u.example.com>
In reply to#67799
David Brown <david.brown@hesbynett.no> writes:
> On 20/08/2019 03:31, Keith Thompson wrote:
>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>>> On 19.08.2019 21:44, Richard wrote:
>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>>> <qi042o$if8$1@dont-email.me> thusly:
>>>>
>>>>> The $ things in the following code are macros from the specified
>>>>> header-only library on GitHub.
>>>>
>>>> Can you tell me where in the standard it allows for $ to be part of an
>>>> identifier?
>>>>
>>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>>
>>> In the future you might risk that people think you're a total novice,
>>> one who doesn't even know the basics of identifiers in C++.
>> 
>> Then I'll risk the same thing.  Can you explain where C++17 permits $
>> in identifiers (or where it permits compilers to permit it)?
>
> It doesn't.
>
>> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
>> and therefore require a diagnostic from any conforming compiler (which
>> implies that gcc is non-conforming).
>
> You get the warning with "-Wpedantic" and an appropriate "-std" C++ 
> standard (and perhaps an appropriate version of gcc).

Can you demonstrate that?  I haven't been able to do so, with several
versions of g++ (up to and including a bleeding-edge version I built
from source a week and a half ago).  Here's the test case I used:

#include <iostream>
int main() {
    const int foo$bar = 42;
    std::cout << foo$bar << "\n";
}

compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
I have on my system.

>> Or perhaps I'm missing something (always a real possibility).
>
> What you are missing is that $ is accepted in identifiers in many 
> compilers, and Alf simply does not care that it is not supported in the 
> standards as long as it is supported in the compilers he uses.

Please don't assume that I missed it just because I didn't discuss it.

My post was about whether the C++ standard permits compilers to
permit $ in identifiers.  (I presume we can all agree that compilers
aren't *required* to accept $ in identifiers.)  C++11 clearly does
permit it, since it explicitly allows "other implementation-defined
characters" in identifiers.  C++17 apparently does not, since it
dropped that wording (apparently in the belief that it was redundant,
but I don't believe it was).

[...]

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#67803

FromIan Collins <ian-news@hotmail.com>
Date2019-08-20 22:22 +1200
Message-ID<gs1vu8Fu65U4@mid.individual.net>
In reply to#67802
On 20/08/2019 21:18, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 20/08/2019 03:31, Keith Thompson wrote:
>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>>>> On 19.08.2019 21:44, Richard wrote:
>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>>>> <qi042o$if8$1@dont-email.me> thusly:
>>>>>
>>>>>> The $ things in the following code are macros from the specified
>>>>>> header-only library on GitHub.
>>>>>
>>>>> Can you tell me where in the standard it allows for $ to be part of an
>>>>> identifier?
>>>>>
>>>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>>>
>>>> In the future you might risk that people think you're a total novice,
>>>> one who doesn't even know the basics of identifiers in C++.
>>>
>>> Then I'll risk the same thing.  Can you explain where C++17 permits $
>>> in identifiers (or where it permits compilers to permit it)?
>>
>> It doesn't.
>>
>>> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
>>> and therefore require a diagnostic from any conforming compiler (which
>>> implies that gcc is non-conforming).
>>
>> You get the warning with "-Wpedantic" and an appropriate "-std" C++
>> standard (and perhaps an appropriate version of gcc).
> 
> Can you demonstrate that?  I haven't been able to do so, with several
> versions of g++ (up to and including a bleeding-edge version I built
> from source a week and a half ago).  Here's the test case I used:
> 
> #include <iostream>
> int main() {
>      const int foo$bar = 42;
>      std::cout << foo$bar << "\n";
> }
> 
> compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
> I have on my system.

Try clang:

$ clang++ -Wpedantic -std=c++17 /tmp/x.cc
/tmp/x.cc:3:18: warning: '$' in identifier 
[-Wdollar-in-identifier-extension]
     const int foo$bar = 42;
                  ^
/tmp/x.cc:4:21: warning: '$' in identifier 
[-Wdollar-in-identifier-extension]
     std::cout << foo$bar << "\n";
                     ^
2 warnings generated.
$ clang++ --version
clang version 8.0.1-svn363027-1~exp1~20190611211629.77 (branches/release_80)

-- 
Ian.

[toc] | [prev] | [next] | [standalone]


#67822

FromKeith Thompson <kst-u@mib.org>
Date2019-08-20 14:21 -0700
Message-ID<lnsgpv354t.fsf@kst-u.example.com>
In reply to#67803
Ian Collins <ian-news@hotmail.com> writes:
> On 20/08/2019 21:18, Keith Thompson wrote:
[...]
>> Can you demonstrate that?  I haven't been able to do so, with several
>> versions of g++ (up to and including a bleeding-edge version I built
>> from source a week and a half ago).  Here's the test case I used:
>>
>> #include <iostream>
>> int main() {
>>      const int foo$bar = 42;
>>      std::cout << foo$bar << "\n";
>> }
>>
>> compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
>> I have on my system.
>
> Try clang:
>
> $ clang++ -Wpedantic -std=c++17 /tmp/x.cc
> /tmp/x.cc:3:18: warning: '$' in identifier
> [-Wdollar-in-identifier-extension]
>     const int foo$bar = 42;
>                  ^
> /tmp/x.cc:4:21: warning: '$' in identifier
> [-Wdollar-in-identifier-extension]
>     std::cout << foo$bar << "\n";
>                     ^
> 2 warnings generated.
> $ clang++ --version
> clang version 8.0.1-svn363027-1~exp1~20190611211629.77 (branches/release_80)

Yes, I had already tried clang.  It allows '$' in identifiers, but warns
about them in conforming mode, which agrees with my interpretation of
what the C++17 standard requires.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#67805

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-20 13:00 +0200
Message-ID<qjgjsu$f6b$1@dont-email.me>
In reply to#67802
On 20/08/2019 11:18, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 20/08/2019 03:31, Keith Thompson wrote:
>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>>>> On 19.08.2019 21:44, Richard wrote:
>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>>>> <qi042o$if8$1@dont-email.me> thusly:
>>>>>
>>>>>> The $ things in the following code are macros from the specified
>>>>>> header-only library on GitHub.
>>>>>
>>>>> Can you tell me where in the standard it allows for $ to be part of an
>>>>> identifier?
>>>>>
>>>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>>>
>>>> In the future you might risk that people think you're a total novice,
>>>> one who doesn't even know the basics of identifiers in C++.
>>>
>>> Then I'll risk the same thing.  Can you explain where C++17 permits $
>>> in identifiers (or where it permits compilers to permit it)?
>>
>> It doesn't.
>>
>>> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
>>> and therefore require a diagnostic from any conforming compiler (which
>>> implies that gcc is non-conforming).
>>
>> You get the warning with "-Wpedantic" and an appropriate "-std" C++ 
>> standard (and perhaps an appropriate version of gcc).
> 
> Can you demonstrate that?  I haven't been able to do so, with several
> versions of g++ (up to and including a bleeding-edge version I built
> from source a week and a half ago).  Here's the test case I used:
> 
> #include <iostream>
> int main() {
>     const int foo$bar = 42;
>     std::cout << foo$bar << "\n";
> }
> 
> compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
> I have on my system.
> 

I was playing on <https://godbolt.org>, with just:

	int a$ = 1;

"--std=c++03  -Wpedantic" gives a warning (testing with gcc trunk).
--std=c++11 and --std=c++17 do not.  (C++98 also warns.)

It seems to be quite specific here.

clang warns on C++11 and C++17 as well as C++03.

So you can get a warning on some choices, but not others.

>>> Or perhaps I'm missing something (always a real possibility).
>>
>> What you are missing is that $ is accepted in identifiers in many 
>> compilers, and Alf simply does not care that it is not supported in the 
>> standards as long as it is supported in the compilers he uses.
> 
> Please don't assume that I missed it just because I didn't discuss it.

Fair enough.

> 
> My post was about whether the C++ standard permits compilers to
> permit $ in identifiers.  (I presume we can all agree that compilers
> aren't *required* to accept $ in identifiers.)  C++11 clearly does
> permit it, since it explicitly allows "other implementation-defined
> characters" in identifiers.  C++17 apparently does not, since it
> dropped that wording (apparently in the belief that it was redundant,
> but I don't believe it was).
> 

I have C11 and C++14 standards conveniently at hand, and both have
"other implementation-defined character" clauses.

If C++17 does not have that, would a $ in an identifier constitute
undefined behaviour (since it is not defined in the standard), and
therefore a compiler can support it, or would it constitute a syntax
error (requiring a diagnostic for conformity) ?

[toc] | [prev] | [next] | [standalone]


#67823

FromKeith Thompson <kst-u@mib.org>
Date2019-08-20 14:59 -0700
Message-ID<lno90j33ci.fsf@kst-u.example.com>
In reply to#67805
David Brown <david.brown@hesbynett.no> writes:
> On 20/08/2019 11:18, Keith Thompson wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>> On 20/08/2019 03:31, Keith Thompson wrote:
>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>>>>> On 19.08.2019 21:44, Richard wrote:
>>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>>>>> <qi042o$if8$1@dont-email.me> thusly:
>>>>>>
>>>>>>> The $ things in the following code are macros from the specified
>>>>>>> header-only library on GitHub.
>>>>>>
>>>>>> Can you tell me where in the standard it allows for $ to be part of an
>>>>>> identifier?
>>>>>>
>>>>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>>>>
>>>>> In the future you might risk that people think you're a total novice,
>>>>> one who doesn't even know the basics of identifiers in C++.
>>>>
>>>> Then I'll risk the same thing.  Can you explain where C++17 permits $
>>>> in identifiers (or where it permits compilers to permit it)?
>>>
>>> It doesn't.
>>>
>>>> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
>>>> and therefore require a diagnostic from any conforming compiler (which
>>>> implies that gcc is non-conforming).
>>>
>>> You get the warning with "-Wpedantic" and an appropriate "-std" C++ 
>>> standard (and perhaps an appropriate version of gcc).
>> 
>> Can you demonstrate that?  I haven't been able to do so, with several
>> versions of g++ (up to and including a bleeding-edge version I built
>> from source a week and a half ago).  Here's the test case I used:
>> 
>> #include <iostream>
>> int main() {
>>     const int foo$bar = 42;
>>     std::cout << foo$bar << "\n";
>> }
>> 
>> compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
>> I have on my system.
>> 
>
> I was playing on <https://godbolt.org>, with just:
>
> 	int a$ = 1;
>
> "--std=c++03  -Wpedantic" gives a warning (testing with gcc trunk).
> --std=c++11 and --std=c++17 do not.  (C++98 also warns.)

All editions of the C++ standard allow universal-character-names in
identifiers, and all restrict them to ranges listed in a table (the
table does not include the code for '$').

C++11 (and apparently C++14) add the "other implementation-defined
characters" wording, which means that a compiler *may* permit '$' in
identifiers (and needn't warn about it).  C++17 dropped it according to
the drafts I have.

As far as I can tell, no version of g++ warns about '$' in an identifier
with "-Wpedantic -std=c++17".  My reading of the C++17 standard is that
such a warning is required, making g++ non-conforming.

It appears that gcc warns about '$' in identifiers with -std=c++98 and
-std=c++03, and does not warn with -std=c++11 or higher.  It looks like
the gcc maintainers responded to the addition of "other
implementation-defined character" in C++11, but did not respond to its
removal in C++17.

clang supports '$' in identifiers as an extension, but always warns
about them with "-std=c++... -Wpedantic", which is conforming behavior
for all versions of the standard.

[...]

> I have C11 and C++14 standards conveniently at hand, and both have
> "other implementation-defined character" clauses.
>
> If C++17 does not have that, would a $ in an identifier constitute
> undefined behaviour (since it is not defined in the standard), and
> therefore a compiler can support it, or would it constitute a syntax
> error (requiring a diagnostic for conformity) ?

It would be a violation of a *diagnosable rule*, requiring at least a
warning.  I don't think it's a syntax error, but there's no required
distinction between syntax errors and other kinds of diagnosable errors.

The rule it violates is in N4700 5.10 [lex.name] paragraph 1:

    Each universal-character-name in an identifier shall designate a
    character whose encoding in ISO 10646 falls into one of the ranges
    specified in Table 2.

('$' is not in Table 2.)  That wording in the C standard would imply
that the behavior is undefined (or that it's a "constraint violation",
if it's in an explicitly marked constraint) but C++ [intro.compliance]
says:

    The set of diagnosable rules consists of all syntactic and
    semantic rules in this document except for those rules containing
    an explicit notation that “no diagnostic is required” or
    which are described as resulting in “undefined behavior”.

The effect is the same: a diagnostic is required.  (If the
implementation chooses to produce an executable after printing the
required diagnostic, I suppose the behavior is undefined by omission.)

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#67838

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-21 10:29 +0200
Message-ID<qjivda$fb2$1@dont-email.me>
In reply to#67823
On 20/08/2019 23:59, Keith Thompson wrote:
> David Brown <david.brown@hesbynett.no> writes:
>> On 20/08/2019 11:18, Keith Thompson wrote:
>>> David Brown <david.brown@hesbynett.no> writes:
>>>> On 20/08/2019 03:31, Keith Thompson wrote:
>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>>>>>> On 19.08.2019 21:44, Richard wrote:
>>>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>>>>>> <qi042o$if8$1@dont-email.me> thusly:
>>>>>>>
>>>>>>>> The $ things in the following code are macros from the specified
>>>>>>>> header-only library on GitHub.
>>>>>>>
>>>>>>> Can you tell me where in the standard it allows for $ to be part of an
>>>>>>> identifier?
>>>>>>>
>>>>>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>>>>>
>>>>>> In the future you might risk that people think you're a total novice,
>>>>>> one who doesn't even know the basics of identifiers in C++.
>>>>>
>>>>> Then I'll risk the same thing.  Can you explain where C++17 permits $
>>>>> in identifiers (or where it permits compilers to permit it)?
>>>>
>>>> It doesn't.
>>>>
>>>>> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
>>>>> and therefore require a diagnostic from any conforming compiler (which
>>>>> implies that gcc is non-conforming).
>>>>
>>>> You get the warning with "-Wpedantic" and an appropriate "-std" C++ 
>>>> standard (and perhaps an appropriate version of gcc).
>>>
>>> Can you demonstrate that?  I haven't been able to do so, with several
>>> versions of g++ (up to and including a bleeding-edge version I built
>>> from source a week and a half ago).  Here's the test case I used:
>>>
>>> #include <iostream>
>>> int main() {
>>>     const int foo$bar = 42;
>>>     std::cout << foo$bar << "\n";
>>> }
>>>
>>> compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
>>> I have on my system.
>>>
>>
>> I was playing on <https://godbolt.org>, with just:
>>
>> 	int a$ = 1;
>>
>> "--std=c++03  -Wpedantic" gives a warning (testing with gcc trunk).
>> --std=c++11 and --std=c++17 do not.  (C++98 also warns.)
> 
> All editions of the C++ standard allow universal-character-names in
> identifiers, and all restrict them to ranges listed in a table (the
> table does not include the code for '$').
> 
> C++11 (and apparently C++14) add the "other implementation-defined
> characters" wording, which means that a compiler *may* permit '$' in
> identifiers (and needn't warn about it).  C++17 dropped it according to
> the drafts I have.
> 
> As far as I can tell, no version of g++ warns about '$' in an identifier
> with "-Wpedantic -std=c++17".  My reading of the C++17 standard is that
> such a warning is required, making g++ non-conforming.
> 
> It appears that gcc warns about '$' in identifiers with -std=c++98 and
> -std=c++03, and does not warn with -std=c++11 or higher.  It looks like
> the gcc maintainers responded to the addition of "other
> implementation-defined character" in C++11, but did not respond to its
> removal in C++17.
> 

I wonder if the change in C++17 was with a view to future uses of $ for
other purposes in C++ (such as for metaclasses)?  Has the status here
changed in C++20 ?


> clang supports '$' in identifiers as an extension, but always warns
> about them with "-std=c++... -Wpedantic", which is conforming behavior
> for all versions of the standard.
> 
> [...]
> 
>> I have C11 and C++14 standards conveniently at hand, and both have
>> "other implementation-defined character" clauses.
>>
>> If C++17 does not have that, would a $ in an identifier constitute
>> undefined behaviour (since it is not defined in the standard), and
>> therefore a compiler can support it, or would it constitute a syntax
>> error (requiring a diagnostic for conformity) ?
> 
> It would be a violation of a *diagnosable rule*, requiring at least a
> warning.  I don't think it's a syntax error, but there's no required
> distinction between syntax errors and other kinds of diagnosable errors.
> 
> The rule it violates is in N4700 5.10 [lex.name] paragraph 1:
> 
>     Each universal-character-name in an identifier shall designate a
>     character whose encoding in ISO 10646 falls into one of the ranges
>     specified in Table 2.
> 
> ('$' is not in Table 2.)  That wording in the C standard would imply
> that the behavior is undefined (or that it's a "constraint violation",
> if it's in an explicitly marked constraint) but C++ [intro.compliance]
> says:
> 
>     The set of diagnosable rules consists of all syntactic and
>     semantic rules in this document except for those rules containing
>     an explicit notation that “no diagnostic is required” or
>     which are described as resulting in “undefined behavior”.
> 
> The effect is the same: a diagnostic is required.  (If the
> implementation chooses to produce an executable after printing the
> required diagnostic, I suppose the behavior is undefined by omission.)
> 

Thanks for filling out the details here.

[toc] | [prev] | [next] | [standalone]


#67839

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-08-21 11:14 +0200
Message-ID<qjj213$814$1@dont-email.me>
In reply to#67838
On 21.08.2019 10:29, David Brown wrote:
> On 20/08/2019 23:59, Keith Thompson wrote:
>> David Brown <david.brown@hesbynett.no> writes:
>>> On 20/08/2019 11:18, Keith Thompson wrote:
>>>> David Brown <david.brown@hesbynett.no> writes:
>>>>> On 20/08/2019 03:31, Keith Thompson wrote:
>>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>>>>>>> On 19.08.2019 21:44, Richard wrote:
>>>>>>>> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> spake the secret code
>>>>>>>> <qi042o$if8$1@dont-email.me> thusly:
>>>>>>>>
>>>>>>>>> The $ things in the following code are macros from the specified
>>>>>>>>> header-only library on GitHub.
>>>>>>>>
>>>>>>>> Can you tell me where in the standard it allows for $ to be part of an
>>>>>>>> identifier?
>>>>>>>>
>>>>>>>> I'm looking at 5.10 in N4659 (Draft C++17) and don't see it.
>>>>>>>
>>>>>>> In the future you might risk that people think you're a total novice,
>>>>>>> one who doesn't even know the basics of identifiers in C++.
>>>>>>
>>>>>> Then I'll risk the same thing.  Can you explain where C++17 permits $
>>>>>> in identifiers (or where it permits compilers to permit it)?
>>>>>
>>>>> It doesn't.
>>>>>
>>>>>> I believe that both foo$bar and foo\u0024bar violate a diagnosable rule
>>>>>> and therefore require a diagnostic from any conforming compiler (which
>>>>>> implies that gcc is non-conforming).
>>>>>
>>>>> You get the warning with "-Wpedantic" and an appropriate "-std" C++
>>>>> standard (and perhaps an appropriate version of gcc).
>>>>
>>>> Can you demonstrate that?  I haven't been able to do so, with several
>>>> versions of g++ (up to and including a bleeding-edge version I built
>>>> from source a week and a half ago).  Here's the test case I used:
>>>>
>>>> #include <iostream>
>>>> int main() {
>>>>      const int foo$bar = 42;
>>>>      std::cout << foo$bar << "\n";
>>>> }
>>>>
>>>> compiled with "g++ -Wpedantic -std=c++17".  No warning from any version
>>>> I have on my system.
>>>>
>>>
>>> I was playing on <https://godbolt.org>, with just:
>>>
>>> 	int a$ = 1;
>>>
>>> "--std=c++03  -Wpedantic" gives a warning (testing with gcc trunk).
>>> --std=c++11 and --std=c++17 do not.  (C++98 also warns.)
>>
>> All editions of the C++ standard allow universal-character-names in
>> identifiers, and all restrict them to ranges listed in a table (the
>> table does not include the code for '$').
>>
>> C++11 (and apparently C++14) add the "other implementation-defined
>> characters" wording, which means that a compiler *may* permit '$' in
>> identifiers (and needn't warn about it).  C++17 dropped it according to
>> the drafts I have.
>>
>> As far as I can tell, no version of g++ warns about '$' in an identifier
>> with "-Wpedantic -std=c++17".  My reading of the C++17 standard is that
>> such a warning is required, making g++ non-conforming.
>>
>> It appears that gcc warns about '$' in identifiers with -std=c++98 and
>> -std=c++03, and does not warn with -std=c++11 or higher.  It looks like
>> the gcc maintainers responded to the addition of "other
>> implementation-defined character" in C++11, but did not respond to its
>> removal in C++17.
>>
> 
> I wonder if the change in C++17 was with a view to future uses of $ for
> other purposes in C++ (such as for metaclasses)?  Has the status here
> changed in C++20 ?
> 
> 
>> clang supports '$' in identifiers as an extension, but always warns
>> about them with "-std=c++... -Wpedantic", which is conforming behavior
>> for all versions of the standard.
>>
>> [...]
>>
>>> I have C11 and C++14 standards conveniently at hand, and both have
>>> "other implementation-defined character" clauses.
>>>
>>> If C++17 does not have that, would a $ in an identifier constitute
>>> undefined behaviour (since it is not defined in the standard), and
>>> therefore a compiler can support it, or would it constitute a syntax
>>> error (requiring a diagnostic for conformity) ?

Herb was thinking about that, at least as a for-the-moment temporary 
scheme allowing exploration, but as mentioned he dropped it because at 
least one company had $-based simple preprocessing.


>> It would be a violation of a *diagnosable rule*, requiring at least a
>> warning.  I don't think it's a syntax error, but there's no required
>> distinction between syntax errors and other kinds of diagnosable errors.
>>
>> The rule it violates is in N4700 5.10 [lex.name] paragraph 1:
>>
>>      Each universal-character-name in an identifier shall designate a
>>      character whose encoding in ISO 10646 falls into one of the ranges
>>      specified in Table 2.
>>
>> ('$' is not in Table 2.)  That wording in the C standard would imply
>> that the behavior is undefined (or that it's a "constraint violation",
>> if it's in an explicitly marked constraint) but C++ [intro.compliance]
>> says:
>>
>>      The set of diagnosable rules consists of all syntactic and
>>      semantic rules in this document except for those rules containing
>>      an explicit notation that “no diagnostic is required” or
>>      which are described as resulting in “undefined behavior”.
>>
>> The effect is the same: a diagnostic is required.  (If the
>> implementation chooses to produce an executable after printing the
>> required diagnostic, I suppose the behavior is undefined by omission.)

There's no need to print anything. /Not/ blinking the caps lock 
indicator for a millisecond is a valid diagnostic. The standard doesn't 
specify what a "diagnostic" or a "diagnostic message" is, that it should 
involve text at all, or that it should be context-independent...

That may sound like a silly argument.

But it's exactly the same kind of argument as the quoted text that it 
responds to: a literal formal interpretation of text that was meant to 
be read with some common sense engaged. To the degree that that quoted 
text is a valid argument, this caps lock non-blink argument is valid.

Of course, both are silly.

It doesn't make sense to assume that kind of absolute formal rigor in 
the standard, and taking the standard's words literally proves that that 
leads to totally absurd consequences.


> Thanks for filling out the details here.


Cheers!,

- Alf

[toc] | [prev] | [next] | [standalone]


#67841

FromKeith Thompson <kst-u@mib.org>
Date2019-08-21 02:55 -0700
Message-ID<ln1rxe3kr6.fsf@kst-u.example.com>
In reply to#67839
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
> On 21.08.2019 10:29, David Brown wrote:
>> On 20/08/2019 23:59, Keith Thompson wrote:
[...]
>>> The effect is the same: a diagnostic is required.  (If the
>>> implementation chooses to produce an executable after printing the
>>> required diagnostic, I suppose the behavior is undefined by omission.)
>
> There's no need to print anything. /Not/ blinking the caps lock 
> indicator for a millisecond is a valid diagnostic. The standard doesn't 
> specify what a "diagnostic" or a "diagnostic message" is, that it should 
> involve text at all, or that it should be context-independent...
>
> That may sound like a silly argument.

Yes, it does.

The standard requires a diagnostic message for certain errors, and
defines a "diagnostic message" as "a message belonging to an
implementation-defined subset of the implementation’s output messages".
The phrase "implementation-defined" means the documentation has to
document it.

gcc's documentation, for example, says:

   * 'How a diagnostic is identified (C90 3.7, C99 and C11 3.10, C90,
     C99 and C11 5.1.1.3).'

     Diagnostics consist of all the output sent to stderr by GCC.

That's for C, but the "C++ Implementation-Defined Behavior" says "Some
choices are documented in the corresponding document for the C
language."

So no, for gcc/g++ not blinking the caps lock is not a diagnostic.

> But it's exactly the same kind of argument as the quoted text that it 
> responds to: a literal formal interpretation of text that was meant to 
> be read with some common sense engaged. To the degree that that quoted 
> text is a valid argument, this caps lock non-blink argument is valid.
>
> Of course, both are silly.
>
> It doesn't make sense to assume that kind of absolute formal rigor in 
> the standard, and taking the standard's words literally proves that that 
> leads to totally absurd consequences.

I prefer to assume that *the standard means what it says* whenever
possible.

In this particular case, I think that the wording of the current
standard, though it's unambiguous, has an unintended consequence.

-- 
Keith Thompson (The_Other_Keith) kst-u@mib.org  <http://www.ghoti.net/~kst>
Will write code for food.
void Void(void) { Void(); } /* The recursive call of the void */

[toc] | [prev] | [next] | [standalone]


#67842

From"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>
Date2019-08-21 12:30 +0200
Message-ID<qjj6fo$gg6$1@dont-email.me>
In reply to#67841
On 21.08.2019 11:55, Keith Thompson wrote:
> "Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com> writes:
>> On 21.08.2019 10:29, David Brown wrote:
>>> On 20/08/2019 23:59, Keith Thompson wrote:
> [...]
>>>> The effect is the same: a diagnostic is required.  (If the
>>>> implementation chooses to produce an executable after printing the
>>>> required diagnostic, I suppose the behavior is undefined by omission.)
>>
>> There's no need to print anything. /Not/ blinking the caps lock
>> indicator for a millisecond is a valid diagnostic. The standard doesn't
>> specify what a "diagnostic" or a "diagnostic message" is, that it should
>> involve text at all, or that it should be context-independent...
>>
>> That may sound like a silly argument.
> 
> Yes, it does.
> 
> The standard requires a diagnostic message for certain errors, and
> defines a "diagnostic message" as "a message belonging to an
> implementation-defined subset of the implementation’s output messages".
> The phrase "implementation-defined" means the documentation has to
> document it.
> 
> gcc's documentation, for example, says:
> 
>     * 'How a diagnostic is identified (C90 3.7, C99 and C11 3.10, C90,
>       C99 and C11 5.1.1.3).'
> 
>       Diagnostics consist of all the output sent to stderr by GCC.
> 
> That's for C, but the "C++ Implementation-Defined Behavior" says "Some
> choices are documented in the corresponding document for the C
> language."
> 
> So no, for gcc/g++ not blinking the caps lock is not a diagnostic.

I'm sorry, that's a simple fallacy.

That g++ doesn't do that now, has no bearing on what it /can/ do.

As far as the formal is concerned g++ can use the non-blinking caps lock 
as a diagnostic.


>> But it's exactly the same kind of argument as the quoted text that it
>> responds to: a literal formal interpretation of text that was meant to
>> be read with some common sense engaged. To the degree that that quoted
>> text is a valid argument, this caps lock non-blink argument is valid.
>>
>> Of course, both are silly.
>>
>> It doesn't make sense to assume that kind of absolute formal rigor in
>> the standard, and taking the standard's words literally proves that that
>> leads to totally absurd consequences.
> 
> I prefer to assume that *the standard means what it says* whenever
> possible.
> 
> In this particular case, I think that the wording of the current
> standard, though it's unambiguous, has an unintended consequence.

Maybe.

For example, I remember `$` being used in the system API in the HP3000. 
That's long ago, 1980s, but presumably use of `$` in system API function 
names was part of the reasons why compilers supported it. And continue 
to support it.

Also, Richard Smith's DR that you linked to (thank you) simply neglects 
to consider the matter, and is worded as if he were unaware.

   * * *

I think this one is just as ill-conceived as his UTF-8 character literal 
limited to ASCII. My impression is that since C++14 there is a stronger 
slant towards really marginal benefit for compiler writers, while 
ignoring the far more significant negative consequences for practical 
programming,  education and knowledge sharing. But it's nothing I can 
prove, I have no statistics.


Cheers!,

- Alf

[toc] | [prev] | [next] | [standalone]


#67843

FromDavid Brown <david.brown@hesbynett.no>
Date2019-08-21 14:22 +0200
Message-ID<qjjd20$bdn$1@dont-email.me>
In reply to#67842
On 21/08/2019 12:30, Alf P. Steinbach wrote:
> On 21.08.2019 11:55, Keith Thompson wrote:

>> In this particular case, I think that the wording of the current
>> standard, though it's unambiguous, has an unintended consequence.
> 
> Maybe.
> 
> For example, I remember `$` being used in the system API in the HP3000.
> That's long ago, 1980s, but presumably use of `$` in system API function
> names was part of the reasons why compilers supported it. And continue
> to support it.
> 

It is not at all unreasonable for compiler implementations to support $
in identifiers in system functions or other "internal" uses, without it
being usable for other cases.  A compiler could view it as part of its
reserved namespace, like __identifiers.  But once they do that, it's
usually easier to allow it in ordinary code than add extra checking to
detect and diagnose it.

I've seen many assemblers that use $ for different reasons - to indicate
local labels, for register names, for hexadecimal numbers, for comments.
 It's awkward for compilers to accept $ identifiers when working with
such lower-level tools - it means some sort of name mangling.

> Also, Richard Smith's DR that you linked to (thank you) simply neglects
> to consider the matter, and is worded as if he were unaware.
> 
>   * * *
> 
> I think this one is just as ill-conceived as his UTF-8 character literal
> limited to ASCII. My impression is that since C++14 there is a stronger
> slant towards really marginal benefit for compiler writers, while
> ignoring the far more significant negative consequences for practical
> programming,  education and knowledge sharing. But it's nothing I can
> prove, I have no statistics.
> 
> 
> Cheers!,
> 
> - Alf

[toc] | [prev] | [next] | [standalone]


Page 1 of 2  [1] 2  Next page →

Back to top | Article view | comp.lang.c++


csiph-web