2

Essentials of my problem: My project consists of both C and C++ files, some string constants (they are hardcoded in C part of project with #define) are required to connect to computer via USB, but if I connect two or more of same type devices, they stop responding because those constants are same. Solution to this problem would be assigning those constants dynamically, from C++ files, so that variable from C++ code could reach C part, where those values are used.

What I have now: Values are defined in C headers as #define IDENTIFIER VALUE (hardcoded), where both VALUE is a C primitive constant an int like 0x1234 or char array like "Some string". For instance:

#define IDENTIFIER1 0x1234
#define IDENTIFIER2 0x5678
#define IDENTIFIER3 "Some string"
#define IDENTIFIER4 "Another string"

I know that methods in C use those identifiers with other macros such as LOBYTE and HIBYTE, also values are passed to some functions.

I tried approaching this problem by replacing the string defines with static cast char[] variable definition wrapped in #ifndef, but compiler noted that the identifiers are initializing non-const variables in some functions or is passed as a parameter.

I successfully compiled code in which i changed defining strings from #define IDENTIFIER VALUE to static const unsigned char IDENTIFIER[] = VALUE;, but I still need to define them in C++.

However I struggle to define hexadecimal numbers like 0x1234. I've found other question including something related to my problem, so far I've tried to define hexadecimal values in following ways (found out that uint8_t is just a typedef of unsigned char, also found some questions about casting numbers to unsigned char and some answers to questions about casting types):

static uint8_t IDENTIFIER[] = {0x12, 0x34, 0};

static const uint8_t IDENTIFIER[] = {0x12, 0x34, 0};

static const uint8_t IDENTIFIER[] = (uint8_t*)0x1234;

static const uint16_t identifier_int = 0x1234;
static const unsigned char IDENTIFIER[3] = identifier_int;

there is a function which uses IDENTIFIERs as arguments, its prototype looks like this:

void foo (uint8_t *bar, /*other arguments*/);

and later this is called like that:

foo(IDENTIFIER, /*other arguments*/)

What I want to achieve: Values should be defined in C++ code, where it should use some method to pass those values to C code.

Questions:

  1. What is best way to pass values from C++ code to C code? What alternatives there are?

Please inform me if I could increase clarity of my question!

Great thanks to @AhmedMasud for helping me out in defining my problem more clearly and giving few tips to clarify questions.

Lycopersicum
  • 529
  • 1
  • 6
  • 17
  • 3
    It looks like you are using `IDENTIFIER` only if it's not define. I don't think I understand what `void setIdentifier` is suppose to do. – François Andrieux Dec 05 '17 at 16:47
  • Agreed, it's not clear what you're trying to achieve with this function. – Oliver Charlesworth Dec 05 '17 at 16:50
  • Probably I misunderstood usage of `static const`. I guess #ifndef guard shouldn't be used there. – Lycopersicum Dec 05 '17 at 16:53
  • 4
    @Lycopersicum Perhaps if you illustrated how you envision using the function, it would help clarify your problem. – François Andrieux Dec 05 '17 at 16:55
  • 2
    You are assuming a lot of things, and are also assuming we'd understand them. preprocessor directives like `#define FOO bar` and then using FOO means literally typing out `bar` wherever `FOO` is used. It happens way before the compiler gets invoked (thus preprocessing). How you go about replacing this in C and C++ is highly subjective. From what I can read so far I think what you want to achieve is akin to compile-time evaluation where you want IDENTIFIER to be evaluated per the value passed per `const`s defined in C++? – Ahmed Masud Dec 05 '17 at 16:56
  • 1
    @FrançoisAndrieux yes, I tried to describe how I imagine definition of `IDENTIFIER` – Lycopersicum Dec 05 '17 at 16:57
  • @AhmedMasud Yes, probably I expressed my opinion wrongly, thank you for your note! – Lycopersicum Dec 05 '17 at 17:00
  • okay given that, then I'll attempt to fix your question and you can tell me if I got the language right. – Ahmed Masud Dec 05 '17 at 17:02
  • I've made several edits to the question to try and focus it, does this help? – Ahmed Masud Dec 05 '17 at 17:27
  • Best rule in programming. If it is not broken don't try and fix it. The code works as is leave it alone. It will compile fine in C++. It may not be the best code but everybody understands it and it works. – Martin York Dec 05 '17 at 17:40
  • @LokiAstari, Thanks for noticing, however I'm making changes because must be updated to work correctly. – Lycopersicum Dec 05 '17 at 18:43
  • Nothing in your question indicates that. You mean it is currently broken as a macro? In what way is it broken? How does changing it to a variable fix the break? – Martin York Dec 05 '17 at 20:40
  • @LokiAstari These macros are used to set some parameter in various platforms, and if they are connected together via USB to same computer, they stop working because of same parameters between devices, I want to make parameter assignment dynamic. – Lycopersicum Dec 05 '17 at 21:15
  • 1
    @Lycopersicum I don't understand that. But that is probably because you are trying to pack a complex explanation into a small comment. It would be better if you updated your question with details about the issue and why the macros don't work. The secret is not to present a solution and ask how to implement, but rather to present a problem and ask for the best technique to solve it. – Martin York Dec 05 '17 at 21:40

2 Answers2

1

Values should be defined in C++ code, where it should use some method to pass those values to C code and then define them.

You can certainly do that in a general sense, but making it work with your existing C code will require changes to that code. Those changes could be distinctly non-trivial.

If I understand correctly macros change all places where IDENTIFIER is used to VALUE before compilation,

Yes, that's a reasonably good characterization.

therefore I think that macros shouldn't be used anymore.

I take you to mean that because you want to set values at run time, you cannot use macros. That's quite right. The least disruptive way to accommodate this in your C code would probably be to declare and use external variables to hold the values. Note well, however, that there is a considerable variety of problems that you might need to solve to convert your C code to work that way.

I expect code to look something like

void setIdentifier(identifier)
{
#ifndef IDENTIFIER
static const unsigned char IDENTIFIER[] = identifier;
#endif
}

as far as I know const should already do it.

No, it won't look much like that at all.

In the first place, you said, reasonably, that you don't want to use macros. In that case the #ifndef IDENTIFIER and #endif have no role to play.

In the second place, you have declared variable IDENTIFIER inside a function, so it has no linkage. You need an external variable if you want one function to set it and a different function to read it.

In the third place, since you'll need an external variable, you'll not be able to use an initializer to set its value. If you declare the variable as a char array (as opposed to a char *), then, you'll need to use strcpy() or a similar function to copy the argument's characters into that array. You can use simple assignment for numeric or pointer variables, however.

  1. I don't know much about interacting with C code from C++ yet, what is best way to pass values from C++ code to C code? What alternatives there are?

Pretty much the same alternatives you have for passing around values inside C++ code: store the value in an accessible variable, or pass it as a function argument. C has no "methods", but for this purpose, C++ methods can be considered a kind of function.

  1. What precautions should I take when assigning those "constants"? I noticed that it is recommended to use static const instead of #define, as mentioned above using macros in this situation probably is unlikely.

The question does not make sense. If you have a constant then you cannot assign a value to it (noting that assigning to is different from initializing). You might use a file-scope const or static const variable if you wanted to set its value at compile time, but the macros in use already accomplish that anyway. Why go to all the work to change?

On the other hand, you need non-const variables if you want to assign to them at runtime. Moreover, you need external variables (non-static) if you want to assign values in one source file that will be read from a different one.

  1. Would static const defined in C++ program be seen in C code?

At file / namespace scope, no, because preventing that is the exact purpose of static in that context. Inside a function or method, no, because the local variables of functions / methods are not visible outside the function / method in which they are declared. So, no.

If you want a variable to which one function or method can write and from which another function or method can read, and at least one of the functions accessing the variable is implemented in C, then you need a file-scope external variable. Such a variable is declared to all users (both C and C++) with a file-scope declaration of this form:

/* "extern" is essential */
extern int IDENTIFIER1;

That would normally be placed in a header file that all sources that access the variable include. Additionally, exactly one source file in the project must define the variable, with code of this form:

/*
 * either the initializer or the absence of "extern" is essential;
 * both together is good form.
 */
int IDENTIFIER1 = 0x1234;
John Bollinger
  • 160,171
  • 8
  • 81
  • 157
0

I would start with simple replace of macros definitions

#define IDENTIFIER1 0x1234
#define IDENTIFIER2 0x5678
#define IDENTIFIER3 "Some string"
#define IDENTIFIER4 "Another string"

with

const auto IDENTIFIER1 = 0x1234;
const auto IDENTIFIER2 = 0x5678;
const auto IDENTIFIER3 = "Some string";
const auto IDENTIFIER4 = "Another string";

After that I would solve further problems step by step if they occur.

273K
  • 29,503
  • 10
  • 41
  • 64