How do I share a constant between C# and C++ code?

后端 未结 5 2162
鱼传尺愫
鱼传尺愫 2020-12-16 21:18

I\'m writing two processes using C# and WCF for one and C++ and WWSAPI for the second. I want to be able to define the address being used for communication between the two

相关标签:
5条回答
  • 2020-12-16 21:38

    Wasn't happy with the other solutions for my use case so coded up a slightly hacky solution that seems to fit the original request better; a constant in one file that can be built into both a C# and a C++ project...

    1. Version information in a .cs file, in a common location.

    Like this:

    // Version.cs
    public static class MyAppVersion
    {
        //build
        public static string Number = "1.0";
        public static string Phase = "Alpha";
    
        //configuration (these are the build constants I use, substitute your own)
    #if BUILD_SHIPPING
        public static string Configuration = "Shipping";
    #elif BUILD_DEVELOPMENT
        public static string Configuration = "Development";
    #elif BUILD_DEBUG
        public static string Configuration = "Debug";
    #else
        "build type not defined"
    #endif
    }
    
    1. Include in C# project using Add Existing Item... [Add As Link]
    2. Include in C++ project (in a .cpp file) with a #include

    Like this:

    //include version information into a .cpp
    #define class namespace
    #define public
    #define static
    #define string const char*
    #include "..\..\Version.cs" //or to where-ever your file is
    ;
    #undef class
    #undef public
    #undef static
    #undef string
    
    1. Reference in C# with: MyAppVersion.Number
    2. Reference in C++ with: MyAppVersion::Number
    0 讨论(0)
  • 2020-12-16 21:45

    You can create a separate C++/CLI project and define all your constants in a .h file. For example, create C++/CLI Class Library project called "ConstantBridge" and a C# project called "CSharpProgram":

    Constants.h

    namespace Constants
    {
        const int MAGIC_NUMBER = 42;
    }
    
    // String literals must be defined as macros
    #define MAGIC_PHRASE "Hello World"
    
    // Since stirngs must be macros it's arguably more consistent 
    // to use `define` throughout. This is for demonstration purpose.
    

    ConstantBridge.h

    #include "Constants.h"
    
    namespace ConstantBridge { public ref class ConstantBridge {
    public:
        // The use of the `literal` keyword is important
        // `static const` will not work
        literal int kMagicNumber = Constants::MAGIC_NUMBER;
        literal String ^ kMagicPhrase = MAGIC_PHRASE;
    };}
    

    CSharpProgram.cs

    Console.WriteLine(ConstantBridge.kMagicNumber); // "42"
    Console.WriteLine(ConstantBridge.kMagicPhrase); // "Hello World"
    

    Now, have the "CSharpProgram" project reference the "ConstantBridge" project. Your other native C++ projects can simply #include "Constants.h".

    As long as you reference only literals from the ConstantBridge project, a runtime dependency will not be generated. You can verify using ILSpy or ILdasm. const in C# and literal in C++/CLI are copied "literally" to the call site during compilation.

    0 讨论(0)
  • 2020-12-16 21:49

    An easier alternative to a method for each constant may be a class containing the constants as instance properties. You could create it in C# and expose it via COM interfaces to C++. That's easier and less error-prone than P/Invoke, since you don't have to worry about getting all the types and names right - it's all done for you by the compiler.

    Note: I have not tried this, I'm only speculating that it should work.

    0 讨论(0)
  • 2020-12-16 22:00

    C# and C++ have differing models for constants. Typically, the constant won't even be emitted in the resulting C++ binary -- it's automatically replaced where it is needed most of the time.

    Rather than using the constant, make a function which returns the constant, which you can P/Invoke from C#.

    Thus,

    #include <iostream>
    const double ACCELERATION_DUE_TO_GRAVITY = 9.8;
    int main()
    {
         std::cout << "Acceleration due to gravity is: " << 
             ACCELERATION_DUE_TO_GRAVITY;
    }
    

    becomes

    #include <iostream>
    extern "C" double AccelerationDueToGravity()
    {
        return 9.8;
    }
    int main()
    {
         std::cout << "Acceleration due to gravity is: " << 
             AccelerationDueToGravity();
    }
    

    which you should be able to P/Invoke from C#.

    0 讨论(0)
  • 2020-12-16 22:00

    When I've had to do that stuff in the past, I've simply added an extra pre-compilation step to the build process which automagically creates one file from another.

    Since your constants will probably be within a class in C#, you can use that as the source file:

    MyClass.cs:
        class MyClass {
            public const int NUM_MONTHS = 12;    //COMMON
            public const int YEAR_BASE = 1900;   //COMMON
        }
    
    grep '//COMMON' MyClass.cs
        | sed -e 's/^ *public const [a-z][a-z]*/#define/'
              -e 's/ *= */ /'
              -e 's/;.*$//'
        >MyClass.h
    grep '//COMMON' MyClass.cs | sed -e 's/ *public //' -e 's/;.*$/;/' >MyClass.hpp
    

    This will give you:

    MyClass.h:
        #define NUM_MONTHS 12
        #define YEAR_BASE 1900
    
    MyClass.hpp:
        const int NUM_MONTHS = 12;
        const int YEAR_BASE = 1900;
    

    Now, getting Visual Studio to perform that step is not something I know how to do. You'll have to investigate whether or not it's even possible. The UNIXy text processing tools are really worth downloading. I have CygWin installed on a few boxes but, for something this localised, you could get away with individual GnuWin32 packages.

    You could probably do a similar job in PowerShell but I'm not really well versed in that.


    Now that's a bit of a kludge so may I suggest a possibly better way for you particular question. Don't use a constant at all. Put the address into a configuration file and have your C# and C++ code read it at startup.

    That way, you get to share the value painlessly and it's configurable in case you ever want to change it in future.

    0 讨论(0)
提交回复
热议问题