Conditional Compile of const static arrays - c++

I am trying to create an error enum and associated text descriptors aligned in the same file. I have a system.cpp file that contains the following:
#define SYSTEMCODE
#include "myerrors.h"
The file myerrors.h contains:
typedef enum errors {
OK,
BADERROR,
LASTENUM } ERR;
#ifndef SYSTEMCODE
extern char const *_errtext[];
#else
const char * _errtext[ERR::LASTENUM +1] = {
"OK",
"BADERROR",
"LASTENUM" };
#undef SYSTEMCODE
#endif
I include system.h in all sources that need error services and they do not define SYSTEMCODE.
I expect that only the system.cpp file will compile the text array and all others will simply have an extern reference. The system.cpp object does not have the _errtext array thus causing a link error. I disable pre-compiled headers and I have tried many variations of this. MSDEV does not get it right.
Any ideas?

Usually, in all the projects I've worked I have seen it done this way.
Create a file myerror.h:
#ifndef _MYERROR_H__
#define _MYERROR_H__
#ifdef __cplusplus
extern "C" {
#endif
typedef enum errors {
OK,
BADERROR,
LASTENUM
} ERR;
extern const char *err_msg(ERR err);
#ifdef __cplusplus
} // extern C
#endif
And then a file myerror.cpp:
#include "myerror.h"
static const char *_errtext[] = {
"OK",
"BADERROR",
"LASTENUM"
};
const char* err_msg(ERR error){
return _errtext[error];
}
That way you just have to include myerror.h from all the files you want and call err_msg(error) whenever you want to print the error in text format. So in another file you'd have:
#include "myerror.h"
int method(){
ERR whatever = OK;
std::cout << err_msg(whatever);
... // Some other stuff here
}
I'm not sure why you want it done in the same file, but as I said, this is how I usually see it done.

Related

proper usage of C dummy functions replacement in different environment

I am trying to add test functions in a suite on both windows and linux machines. On linux machines i want the real functions to be added and on windows machine i want the dummy UnsupportedFunction to be added so that i can have same number of functions on both environments.
I have the following code
void UnsupportedFunction(struct1* test)
{
//dummy function in C
}
// following functions defined else where and gets added only if its linux box
#if ENV_LINUX
extern void linuxOnlyFunc1(struct1* test);
extern void linuxOnlyFunc2(struct1* test);
extern void linuxOnlyFunc3(struct1* test);
extern void linuxOnlyFunc4(struct1* test);
#endif
static struct1* addTest(params, TestFunction fnPtr) {
...
}
static void addTestToSuite (struct1* suite,
input devices,
TestFunction testFunction,
const char* testName,
const char* testDescription)
{
TestFunction fnPtr = UnsupportedFunction;
#if ENV_LINUX
fnPtr = linuxOnlyFunc1;
#endif
LinWB_Util_AddTest(params, fnPtr);
}
the issue is since i have lot of tests to be added to the suite, i have to make an ugly if-defines on all the entries. To get rid of these i have to abstract with a function call but, those externed functions doesnt exist on windows env and i end up getting compiler errors or warnings (considered errors).
how can one design this in a better way ?
How about something like
#if ENV_LINUX
extern void linuxOnlyFunc1(struct1* test);
extern void linuxOnlyFunc2(struct1* test);
extern void linuxOnlyFunc3(struct1* test);
extern void linuxOnlyFunc4(struct1* test);
#else
#define linuxOnlyFunc1 UnsupportedFunction
#define linuxOnlyFunc2 UnsupportedFunction
...
#endif
I haven't tested this, so it might need some tweaking, but you could do something like this:
#if ENV_LINUX
#define linux_only(x) extern void x(struct1* test);
#else
#define linux_only(x) inline void x(struct1* test) { UnsupportedFunction(test); }
#endif
linux_only(linuxOnlyFunc1);
linux_only(linuxOnlyFunc2);
linux_only(linuxOnlyFunc3);
linux_only(linuxOnlyFunc4);
You could use include files to store your function declarations. Thus you dont't have to write them into every source file. And if the functions turn out to be undefined, just write such functions.
upon request, I elaborate.
You create a file called "fakefuns.h" which contains your function declarations:
#if ENV_LINUX
extern void linuxOnlyFunc1(struct1* test);
extern void linuxOnlyFunc2(struct1* test);
extern void linuxOnlyFunc3(struct1* test);
extern void linuxOnlyFunc4(struct1* test);
#endif
Then you can include these definition in every source file by adding
#include "fakefuns.h"
into the source file, preferably near to the first line. And in one source file, you actually implement these functions, both for Linux and Windows. And if they should not to any work in Windows, the implementations will be very simple.

GCC: linker error when working with old C code

I'm running into a mysterious situation with the GCC compiler. So I've got the following files:
//main.cpp
#include "mleak_cpp.h"
int main(int argc, char* argv[])
{
foo();
__memory_malloc(10,"hello",5);
return 0;
}
//mleak_cpp.h
......
void foo(void);
void* __memory_malloc(size_t size, const char* file, int line);
//mleak_cpp.cpp
//definitions of the functions;
void foo(void){printf("foo\n");
void* __memory_malloc(size_t size, const char* file, int line){
printf("%s,%d\n",file,line);
InitDoubleLinkList();
void* p = malloc(size);
if(p == NULL)
return NULL;
__DuLinkList* pListNode;
pListNode = (__DuLinkList*)malloc(sizeof(__DuLinkList));
pListNode->address = p;
pListNode->memorysize = size;
pListNode->file = file;
pListNode->line = line;
InsertBlockToList(pListNode);
return p;
}
For some reason, the call to void foo(void) is fine, but the call to "__memory_malloc" goes down with a linker error, "undefined reference" blah blah. What's the difference between the two functions that causes the different behaviour?
I tried adding "extern C" to the "#include" directive, so main.cpp reads:
extern "C"{
#include "mleak_cpp.h"
}
and adding the keyword "extern" before the declarations of the functions, and this time the call to "foo()" fails too with the same error.
I appreciate any help from you guys
You're placing extern "C" in the wrong place.
If main.c is truly a C file, and mleak_cpp.cpp is truly a C++ function, then you need to put an extern "C" ahead of the definition of __memory_malloc() like so:
extern "C" void* __memory_malloc(size_t size, const char* file, int line){
// ...
}
If you put extern "C" in the mleak_cpp.h file, it needs to be guarded:
#ifdef __cplusplus
extern "C" {
#endif
/* ... body of header ... */
#ifdef __cplusplus
}
#endif
Also, it's not clear why foo works in your example above, when one file calls __foo() but the other file defines foo(). I assume something more is at play, such as an editing error in your question.
extern "C" is for C++, not C, and tells it that the function's name shouldn't be mangled. In C code, you should never see this. Generally, you put it in header files, and you guard it, like this:
#ifdef __cplusplus
extern "C" {
#endif
/* C and C++ compatible header file body here */
#ifdef __cplusplus
} /* end extern "C" */
#endif
If you do it this way though, you need to include the header file in both your C and C++ files, so that the C++ compiler knows to use C linkage.
You can put the extern "C" in front of the function definition in C++ instead and leave it out of the header, but this only works if you only include the headers in C code, so it's recommended to do it the way I pointed out above.

Error C2059: syntax error : 'string'

I have looked at other posts and to be honest I am still not sure what is causing the problem. I am programming in Visual Studio and
I have the following code: (this is a C main)
int main(int arc, char **argv) {
struct map mac_ip;
char line[MAX_LINE_LEN];
char *arp_cache = (char*) calloc(20, sizeof(char)); //yes i know the size is wrong - to be changed
char *mac_address = (char*) calloc(17, sizeof(char));
char *ip_address = (char*) calloc(15, sizeof(char));
arp_cache = exec("arp -a", arp_cache);
It uses the following cpp code:
#include "arp_piping.h"
extern "C" char *exec(char* cmd, char* arp_cache, FILE* pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL) {
strcat(arp_cache, buffer);
}
}
_pclose(pipe);
return arp_cache;
}
With the matching header file:
#ifndef ARP_PIPING_H
#define ARP_PIPING_H
#endif
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
#include <stdio.h>
#include <string.h>
extern "C" char *exec(char* cmd, char* arp_cache, FILE* pipe);
#undef EXTERNC
But I keep on getting the following errors:
1>d:\arp_proto\arp_proto\arp_piping.h(14): error C2059: syntax error : 'string'
1>main.c(22): warning C4013: 'exec' undefined; assuming extern returning int
1>main.c(22): warning C4047: '=' : 'char *' differs in levels of indirection from 'int'
Please can I get some help, I have looked at other posts regarding the c2059 but am still getting nowhere
Change your exec declaration to use the EXTERNC macro you have taken pains to define.
EXTERNC char *exec(char* cmd, char* arp_cache, FILE* pipe);
I ran into this compilation error when adding an enum to a project. It turned out that one of the values in the enum definition had a name clash with a preprocessor #define.
The enum looked something like the following:
// my_header.h
enum Type
{
kUnknown,
kValue1,
kValue2
};
And then elsewhere there was a #define with the following:
// ancient_header.h
#define kUnknown L"Unknown"
Then, in a .cpp somewhere else in the project, both of these headers were included:
// some_file.cpp
#include "ancient_header.h"
#include "my_header.h"
// other code below...
Since the name kUnknown was already #define'd, when the compiler came to the kUnknown symbol in my enum, it generated an error since the symbol was already used to define a string. This caused the cryptic syntax error: 'string' that I saw.
This was incredibly confusing since everything appears to be correct in the enum definition and compiles just fine on it's own.
It didn't help that this was in a very large C++ project, and that the #define was being transitively included in a completely separate compilation unit and was written by someone 15 years ago.
Obviously, the right thing to do from here is rename that terrible #define to something less common than kUnknown, but until then, just renaming the enum value to something else works as a fix, e.g.:
// my_header.h
enum Type
{
kSomeOtherSymbolThatIsntDefined,
kValue1,
kValue2
};
Anyway, hopefully this answer is helpful for someone else, since the cause of this error stumped me for a good day and a half.
extern "C" is used to tell the compiler to make it as C grammer, but your mean is to declear a extern function called exec. you just make fusion to the differ of this. so rewrite your code like this in arp_piping.h:
/*extern "C"*/ char *exec(char* cmd, char* arp_cache, FILE* pipe);
and then del the preffix of extern "C" in cpp file.
if you want to comiler them with C grammer, just setting in the cpp which call for the function exec, so write like this:
extern "C" {
#include "arp_piping.h"
}

Warning: 'void checkGlError(const char*)' used but never defined

I'm compiling a Shared library using Android NDK r6b. All classes are C++.
I have the following two classes:
Utils.hpp
#ifdef USE_OPENGL_ES_1_1
#include <GLES/gl.h>
#include <GLES/glext.h>
#else
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#endif
#include <android/log.h>
// Utility for logging:
#define LOG_TAG "ROTATEACCEL"
#define LOG(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#ifdef __cplusplus
extern "C" {
#endif
static void checkGlError(const char* op);
#ifdef __cplusplus
}
#endif
Utils.cpp
#include "Utils.hpp"
#ifdef __cplusplus
extern "C" {
#endif
static void checkGlError(const char* op) {
for (GLint error = glGetError(); error; error
= glGetError()) {
LOGI("after %s() glError (0x%x)\n", op, error);
}
}
#ifdef __cplusplus
}
#endif
When I want to use this function in other C++ files I #include "Utils.hpp". But, in those files I get an error:
undefined reference to `checkGlError'
Why am I getting this warning?
You've made it static. It only lives in that specific translation unit therefore. The solution is to remove the static keyword.
The warning is telling you that in the header file you "promised" there would be a definition in that translation unity if one was needed, but one has not been provided and it was needed.
static void checkGlError(const char* op);
It is a static function, that means, it has internal linkage, and therefore cannot be called from another translation unit.
Remove the static keyword from it's declaration as well as from it's definition, and it would work fine.

Referencing C functions in static library from C++

I have a static library of functions written in C. Let's say the header file is called myHeader.h and looks like:
#ifndef MYHEADER_H
#define MYHEADER_H
void function1();
void function2();
#endif
function1 and function2 aren't anything too special. Let's say they exist in a file called impl1.c which looks like:
#include "myHeader.h"
void function1() {
// code
}
void function2() {
// more code
}
All of the code mentioned so far is compiled into some static library called libMyLib.a. I'd rather not modify any of the code used to build this library. I also have a C++ header (cppHeader.h) that looks like:
#ifndef CPPHEADER_H
#define CPPHEADER_H
class CppClass {
private:
double attr1;
public:
void function3();
};
#endif
Then cppHeader.cpp looks like:
#include "cppHeader.h"
#include "myHeader.h"
// constructor
CppClass::CppClass(){}
void CppClass::function3() {
function1();
}
When I try to compile this, I get an error about an undefined reference to function1(). I believe that I've linked everything properly when compiling. I'm pretty rusty in my C++. I'm sure that I'm just doing something stupid. I hope that my simple example code illustrates the problem well enough.
Thanks in advance for any help!
The other solution (to the one suggested originally by Yann) is to surround your "C" header with:
#ifdef __cplusplus
extern "C" {
#endif
#ifdef __cplusplus
}
#endif
Which saves you from having to remember to do:
extern "C" {
#include "foo.h"
}
every place you use foo.h
Make sure to use:
extern "C" {
#include "myHeader.h"
}
Or else the C++ compiler will generate symbol names which are name-mangled.