0

I have an old MCPP project which was used as a communication layer between C++ code which runs on machines and C# which runs on a desktop computer. Recently we decided to try and kill this "glue" project.

This project has in it a few lists of constants which are used in the communication and these will be preferably used as an external link in both, C++ and C#.

A colleague how has done a similar thing before used the following trick to keep changes to the constants in one place:

#if !__cplusplus
    public const string
#else
    static const TCHAR* const
#endif
                                XML_V1_TagRoot = "r";

The __cplusplus is set depending on the compiler, so the prepeocessor makes each compiler see what it can compile.

Now I have the problem with a bunch of #define statements of the type:

#define TX_TAG2xHWID_PARAMETER  _T("PR")

Where _T() is a macro. So I tried the following:

#if __cplusplus
    #define     TX_TAG2xHWID_PARAMETER _T("PR")
#else
    internal const string   TX_TAG2xHWID_PARAMETER = "PR";
#endif

Which does not work because C# has no value for the defines. source

Then I tried:

#if __cplusplus
    #define                 TX_TAG2xHWID_PARAMETER \
#else
    internal const string   TX_TAG2xHWID_PARAMETER =
#endif

#if __cplusplus
                                                _T(\
#endif
                                                    "PR"
#if __cplusplus
                                                        )
#else
                                                        ;
#endif

Here the problem is that C# does not allow a multiline #define.

Basically the issue is that a #define is a preprocessor instruction in itself, but should be executed only if the file is compiled in a C++ project.

I have also played with the idea of making the C# project think it is a comment, with placing /* and */ into a different #if, but I had no success there.

So, does anyone know a solution how I can make the C# compiler not complain about that line which it should never try to compile?

Ramzi Khahil
  • 4,932
  • 4
  • 35
  • 69
  • 3
    Why are you even attempting to put c++ and c# in the same file? Are you trying to kill a glue project with yet another one? – Camilo Terevinto Mar 07 '18 at 14:19
  • 6
    We see the occasional code that's correctly tagged as both C and C++'; this might the first about a polyglot C++ / C# question. – MSalters Mar 07 '18 at 14:19
  • What do you mean "Which does not work because C# has no value for the defines." ? It appears that C++ will have a #define TX_TAG2xHWID_PARAMETER, and c# will have an `internal const string` – Martin Bonner supports Monica Mar 07 '18 at 14:23
  • Do you actually ever create Unicode builds? If not, just remove the _T() macros entirely. They were a useful hack for MS to support both types in libraries like MFC, but they should never have appeared in user code. – Martin Bonner supports Monica Mar 07 '18 at 14:29
  • C# does not have a pre-processor, it only supports conditional compilation with #if. The symbols you test with #if can only be a project setting. This is not a problem you have to solve, it has only one string type and one language syntax. So none of these #defines can be relevant. – Hans Passant Mar 07 '18 at 14:33
  • @MartinBonner: They also made sense in Windows 95-ME, but I agree with the suggestion now. ME has been EOL for over a decade now. Nobody is writing code for non-Unicode Win32 platforms anymore. – MSalters Mar 07 '18 at 14:33
  • @MSalters : Lots of people are still writing ANSI builds to run on Unicode Win32 though. In fact, if the OP is generating Unicode only builds, he still has the same problem: he needs L"PR" for C++ and "PR" for C#. – Martin Bonner supports Monica Mar 07 '18 at 14:36
  • @MartinBonner: I know, but `_T` only makes sense in codebases that are compatible with both ANSI and Unicode builds. If you choose either, you choose `""` or `L""`. – MSalters Mar 07 '18 at 14:40
  • As I mentioned before, the C++ part is compiled into an executable which runs on machines, no windows or anything is on there. It is a completly inhouse thing. And since the company is supporting machines that are 15+ years old, I cannot change the `_T` without talking to half of the staff from another department. And my boss said "Try to keep it in one file". *** But thanks for all your inputs, I appreciate your interest and your answers. *** – Ramzi Khahil Mar 07 '18 at 15:28

4 Answers4

0

One possible solution is to give C# a function called _T (which just returns its argument), and then stick with the original approach:

#if !__cplusplus
    public const string
#else
    static const TCHAR* const
#endif
                                TX_TAG2xHWID_PARAMETER = _T("PR");
dessert
  • 248
  • 6
  • 15
0

A completely different approach (which is why it is a separate answer), is to generate both the C++ header file and the C# file at build time with a script. That way the actual source that needs editing is something like

output_text XML_V1_TagRoot "r"
output_text TX_TAG2xHWID_PARAMETER "PR"
output_int  FUNKY_INT_PARAM 43

and the messy #ifs are all produced by the script.

0

Have you considered putting the strings in resources? Both of those can be accessed from C++ or C# using symbolic names and the strings will live in one place and have no issues due to differences in string escapes.

You can also introduce a step into your build that takes a list of strings and their symbolic names and creates two output files: one for C++ and one for C# with an important comment at the top:

// This file is machine generated. To add a constant, edit the file xxxxx
// and rebuild with the command xxxx

This will, at the very least, put all the strings and symbol names in exactly one place at the cost of slightly complicating your build process. And yes, this is exactly the same as using string resources except that you're using a home-cooked tool/script.

plinth
  • 48,267
  • 11
  • 78
  • 120
-1

Unless you have a good reason to keep TX_TAG2xHWID_PARAMETER and similar parameters inlined, you might replace your

#if __cplusplus
    #define     TX_TAG2xHWID_PARAMETER _T("PR")
#else
    internal const string   TX_TAG2xHWID_PARAMETER = "PR";
#endif

with

#if __cplusplus
    LPCTSTR     TX_TAG2xHWID_PARAMETER = _T("PR");
#else
    internal const string   TX_TAG2xHWID_PARAMETER = "PR";
#endif
rs232
  • 1,248
  • 8
  • 16