Exchange source files between C # and C ++

I have a project that is mainly written in C #. I need to define a class for the entire error number "defines" for the API of this project. I am trying to avoid writing / modifying one of my many code generators to achieve this.

What I would like to do is be able to #include content (e.g. defile an error) directly in a C / C ++ project. I defined them in C # as follows, and I did not use the enumeration for the things you will see here:

 using System; namespace ProjectAPI { [Serializable] public sealed class ProjectError { public enum ProjectErrorClass { None = -1, Undefined = 0, Login, Store, Transaction, Heartbeat, Service, HTTPS, Uploader, Downloader, APICall, AutoUpdate, General } public enum ProjectErrorLevel { Unknown = -1, Success = 0, Informational, Warning, Critical, }; /// <summary> /// PROJECT_ERROR_BASE - This is the base for all Project defined errors in the API. Project Errors are defined as follows: /// ProjectAPI error values are 32 bit values defined as follows: /// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1 /// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 /// +---+---------------+-----------------------+------------------+ /// |Sev|Error Code Base| Error Class |Unique Error Code | /// +---+---------------+-----------------------+------------------+ /// where /// /// Sev - is the severity code of the error (2 bits), and is defined as follows: /// 00 - Success (non-fatal) 0x00 /// 01 - Informational 0x01 /// 10 - Warning 0x02 /// 11 - Error 0x03 /// /// Error Code Base - is the starting point of all Project Errors, and is set at 0xA4 (8 Bits). /// /// Error Class - is the error class, or API "Module" that caused the error (12 bits). /// /// Code - the unique error code (10 bits). (0 - 1,023 (0x3FF)). /// </summary> private static readonly int ERR_SHIFT = 0x1E; private static readonly int BASE_SHIFT = 0x16; private static readonly int CLASS_SHIFT = 0x06; private static readonly int PROJECT_SEV_SUCCESS = 0x00; private static readonly int PROJECT_SEV_INFO = 0x01; private static readonly int PROJECT_SEV_WARN = 0x02; private static readonly int PROJECT_SEV_ERROR = 0x03; private static readonly int PROJECT_ERROR_BASE = 0xA5; /// <summary> /// Project Error Class Constants: /// </summary> private static readonly int PROJECT_ERROR_CLASS_UNDEF = 0x0010; /// Undefined. private static readonly int PROJECT_ERROR_CLASS_LOGIN = 0x0020; /// LoginClass Error. private static readonly int PROJECT_ERROR_CLASS_STORE = 0x0040; /// Store Error. private static readonly int PROJECT_ERROR_CLASS_TRANS = 0x0080; /// Transaction Error. private static readonly int PROJECT_ERROR_CLASS_HEART = 0x0100; /// HeartBeat (Project Health Monitor) Error. private static readonly int PROJECT_ERROR_CLASS_SERV = 0x0200; /// Service Error. private static readonly int PROJECT_ERROR_CLASS_HTTP = 0x0400; /// HTTP/HTTPS Error. private static readonly int PROJECT_ERROR_CLASS_UPLOAD = 0x0800; /// Upload (Transactions) Error private static readonly int PROJECT_ERROR_CLASS_DOWNLOAD = 0x1000; /// Download (Transactions) Error private static readonly int PROJECT_ERROR_CLASS_APICALL = 0x2000; /// API Command/call error. private static readonly int PROJECT_ERROR_CLASS_UPDATE = 0x4000; /// Auto-Updater Errors. private static readonly int PROJECT_ERROR_CLASS_GEN = 0x8000; /// General Error. public static readonly int PROJECT_ERROR_UNKNOWN_ERROR = ProjectErrCode(PROJECT_SEV_ERROR, PROJECT_ERROR_CLASS_GEN, 0x001); // Was... // (((PROJECT_SEV_ERROR << ERR_SHIFT) | PROJECT_ERROR_BASE << BASE_SHIFT) | ((PROJECT_ERROR_CLASS_UNDEF << CLASS_SHIFT) | 0x0001)); public static readonly int PROJECT_ERROR_UNKNOWN_HEARTBEAT_ERROR = ProjectErrCode(PROJECT_SEV_ERROR, PROJECT_ERROR_CLASS_HEART, 0x001); ...Snip... 

...

I understand that there are other things that I could contribute to Enums, however my goal is to put this source together with the C ++ compiler. (In the example above, there are no functions, namely ProjectErrCode() , which builds the final integer value of the OTF error code when called from the API.)

I created error constants, as can be seen from the comments, and I can return to this, but I would prefer to write similar classes - one in C #, one in C ++, which can construct / deconstruct error codes. My functions return error severity, error class, etc. The developer can ignore it, register, transfer it to the user interface, etc.

If I only had 5 or 10 error codes, this was not a problem. But I'm over 100 and really don't want to support .cs and .h files with duplicate information. I can manage them in the .h file and read the CS code, but this is almost the same job as writing (modifying) the code generator.


How can I #define go to a single source file so that the C # compiler can compile it, just like the C / ++ compiler? I could just simply #include "ProjectErrors.cs" - the file name is not a problem. I started thinking that I can do this with #define , using using System; but pretty much hanged him.

+6
source share
2 answers

1) Use a preprocessor. Some ifdefs and define should do the trick, but that would be very dirty.

2) Use C ++ / CLI. C ++ / CLI is a variant of C ++ that is compiled into .Net assemblies. Although .Net types and native types are separate objects, transitions between them are possible.

For example, you define a header as completely native code with its own enumerations and constants; you can include this header both in a 100% project and in a C ++ / CLI project, which will also provide conversion ( see this stream ) of transfers to the corresponding .Net.

If you don’t want to have this intermediate conversion level, C ++ / CLI also gives you the full power of C ++ macros, so you can create a file with macros like ENUM_HEADER and CONSTANT and evaluate them into appropriate managed or native forms quite clean and in a simple way (which you cannot do with C # because it has a much weaker preprocessor). The result of the assembly will be essentially this header and corresponding macro definitions, and nothing more.

3) Define the values ​​defined in some external file (XML, INI, independently ...) and implement the loading logic in both C # and C ++ (this may be the cleanest solution).

+4
source

One option is to use T4 : it is a code generation language built into Visual Studio. It is mainly used in C #, but C ++ works apparantly too .

One of the reasons it will be difficult for you to work with the preprocessor is that C # and C ++ have the same syntax for comments: you cannot hide the incompatible C # syntax for the C ++ preprocessor using a comment. However, you can try VB :).

+4
source

Source: https://habr.com/ru/post/957863/


All Articles