Passing arguments by reference in header file - c++

I have 3 files:
file1.h
#ifndef FILE_H_INCLUDED
#define FILE_H_INCLUDED
#include <stdbool.h> // To prevent unknown type 'bool' error
bool parse(char** &buffer);
#endif
file1.cpp
#include "file1.h"
#include <iostream>
using namespace std;
bool parse(char** &buffer) {
buffer[0] == "test";
}
And file2.cpp includes file1.h and calls parse() with a char **buffer;
When compiling I get:
error: expected ';', ',' or ')' before & token
What am I missing?
EDIT: I'm building a project that uses raw sockets, and it's mostly C code.

You are using a C compiler, not a C++ compiler.

I think what you're really trying to do is to pass an array of char pointers, therefore you could change the function to
bool parse(char** buffer);

The compiler, in C language mode, is complaining about the & symbol:
bool parse(char ** &buffer)
The C language does not allow the & character in that context.
However, it is valid C++ syntax, as the function is requiring a pointer passed by reference.
As others have said, switch to a C++ compiler or tell your compiler to compiler the file as C++ language.

This clue:
bool parse(char** &buffer) {
buffer[0] == "test";
}
Indicates that 'buffer' is to be some sort of reference to some sort of array of strings. Not sure why it is returning a bool (which you overlooked, anyway.)
You should consider:
// a std::vector of std::string
typedef std::vector<std::string> StrVec_t;
// parse can easily add individual std::strings
// to the std::vector (from some unknown source)
bool parse (StrVec_t& buffer)
{
buffer.push_back(std::string("test")); // tbd - where did 'test' come from?
return(true); // and add some meaning to this, or perhaps remove
}
// and is used as
// ...
StrVec_t myWords;
// ...
// ...
(void)parse(myWords); // update myWords from some other source
// ... // example of how to discard bool

Related

Is there any way to change function prototypes at compile time in C++?

suppose you have to write code that should compile under C++,C++11,C++17,etc.
A function like this for example.
bool Ispalindrome(const std::string &str)
{
// Code
}
That compiles under all C++ implementations. But if you want to use the old and the new the C++17 string_view feature you have deal with something similar to
#ifdef LEGACYCPP
bool Ispalindrome(const std::string &str)
{
// Code
}
#elseif CPP17
bool Ispalindrome(std::string_view str)
{
// OMG Repeated Code
}
#endif
Using conditional compiling is right, but have to repeat code.
Is there any way to choose a function prototype at compile time ? Or other way to circumvent double coding ? (in situations where it can be applied)
Thanks
In a header file, you'll need to do something like
#if __cplusplus >= 201703L
#include <string_view>
bool Ispalindrome(std::string_view str);
#else
#include <string>
bool Ispalindrome(const std::string &str);
#endif
In your definition, you'll need to include the header and then do
#if __cplusplus >= 201703L
bool Ispalindrome(std::string_view str)
#else
bool Ispalindrome(const std::string &str)
#endif
{
// OMG no repeated code
}
__cplusplus is specified in the standard, and is predefined in every compilation unit. 201703L indicates a C++17 compiler, larger values more recent standards.
This assumes an implementation (compiler and library) that correctly claims compliance with the respective C++ standard.
If you can be sure that the code section of your function will be equivalent in each case, then you can use a macro definition for the parameter list:
#ifdef ISCPP17
#define PALIN_PARAMS std::string_view str
#else
#define PALIN_PARAMS const std::string& str
#endif
bool Ispalindrome(PALIN_PARAMS)
{
// Code
}
#undef PALIN_PARAMS
There are, of course, many variations on this theme: you could leave out the "str" part in the macro definition and have (PALIN_PARAMS str) in the signature. But, using "as is" will also allow for multiple parameters with different types.
But I'm not sure this sort of thing will pass the Inquisitions of the C++ Puritans.
Another (possibly more robust) way would be to use conditional compilation blocks with using (or typedef) statements to define argument types:
#ifdef ISCPP17
using cnststrg = std::string_view; // Or typedef std::string_view cnststrg;
#else
using cnststrg = const std::string&;
#endif
bool Ispalindrome(cnststrg str)
{
// Code
return true;
}
Provided it's exactly repeated code then, do following minor change:
#ifdef CPP17
bool Ispalindrome(std::string_view str)
#else // all versions of LEGACYCPP
bool Ispalindrome(const std::string &str)
#endif
{
// Same Code
}
If a minor part of function is unique to versions, then apply the above same trick there too.

cgo Calling functions defined in a C++ (that are in namespaces)

I have a library that I want to use which only provides C++ header files and a static library. Go is unable to parse the namespaces that it is wrapped in.
I have looked at this: How to use C++ in Go? and it makes sense, but there are no namespaces involved there.
This is the C++ code in question that when imported causes issues (only the beginning shown):
#pragma once
#include <stdint.h>
namespace ctre {
namespace phoenix {
And here is the result of compiling:
./include/ctre/phoenix/ErrorCode.h:4:1: error: unknown type name 'namespace'
namespace ctre {
^~~~~~~~~
./include/ctre/phoenix/ErrorCode.h:4:16: error: expected '=', ',', ';', 'asm' or '__attribute__' before '{' token
namespace ctre {
Is there any way that I can provide a C wrapper which avoids this problem?
I figured it out by creating a C wrapper header file. Then I created a CPP file which bridges said C interface with the library CPP headers and library.
The C header understands my library object as a void pointer, and my CPP implementation has to cast it in order to access all of its functions.
The extern "C" part is very important and prevent Go from freaking out - It prevents the CPP compiler from mangling function names.
Of course, also link the binary with the proper LDFLAGS.
phoenix.h
typedef void CTalon;
#ifdef __cplusplus
extern "C" {
#endif
CTalon* CTRE_CreateTalon(int port);
void CTRE_Set(CTalon* talon, double output);
void CTRE_Follow(CTalon* slave, CTalon* master);
#ifdef __cplusplus
}
#endif
phoenix.cpp
#include "phoenix.h" // My C wrapper header
#include "ctre/phoenix/motorcontrol/can/TalonSRX.h" // Actual CPP header from library
#define TALON(ctalon) ((ctre::TalonSRX*) ctalon) // Helper macro to make converting to library object easier. Optional
namespace ctre { // Specific to my library which has a lot of long namespaces. Unrelated to problem
using ctre::phoenix::motorcontrol::ControlMode;
using ctre::phoenix::motorcontrol::can::TalonSRX;
}
extern "C" {
CTalon* CTRE_CreateTalon(int port) {
return (CTalon*) new ctre::TalonSRX(port);
}
void CTRE_Set(CTalon* talon, double output) {
TALON(talon)->Set(ctre::ControlMode::PercentOutput, output);
}
void CTRE_Follow(CTalon* slave, CTalon* master) {
TALON(slave)->Follow(*(TALON(master)));
}
}

Calling C++ function from a C code

So I have looked here and here and at a few other links mentioned in the first question and I have the following code already:
The .cpp file:
#include "arp_piping.h"
#include <string>
#include <iostream>
#include <stdio.h>
std::string exec(char* cmd, FILE* pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
std::string result = "";
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result += buffer;
}
_pclose(pipe);
return result;
}
The header/linker file:
#ifndef ARP_PIPING_H
#define ARP_PIPING_H
#endif
#ifdef __cplusplus
#define EXTERNC extern "C"
#else
#define EXTERNC
#endif
my function goes here something like
EXTERNC .....exec(char* cmd, FILE* pipe) ????
#undef EXTERNC
My question is what goes in the bit above as I am unsure what to be typing. I am trying to call the function in the .cpp file from my C main function int main(int argc, char** argv) {}
To call C++ functions from C you need to do two things. 1) Let the C++ code know it's going to be used by C so that it can generate C-friendly symbols. 2) Hide any functionality that C can't understand.
The first part is easily achieved by simply defining the functions as you would in C (I.E. don't use any C++ only features like namespaces) and then wrapping them in an extern "C" block if C++ is defined. You basically want your header file to contain C-only code, and then just open the extern block at the top, and close it at the bottom of the file (my example will make this more clear).
The second part is a little trickier, but not too difficult. In your case, your function returns a std::string which is a C++ only class. It can not be used in C and therefore either needs to be replaced with something that can be used in C, or it needs to be hidden behind something that C can use. For the sake of argument let's assume you can't replace std::string with say, char*. In this case you need to hide std::string from the C-facing code. The common way of doing this is to use an opaque pointer.
Basically, the C-facing code deals only with a pointer to something. That something it neither knows about, nor cares about. The C++ code is free to use a std::string internally, but must make sure to hide it before interfacing with the C API. In my example, you can see I've provided an opaque pointer to a struct I've called cppstring.
In the source file, cppstring is just a struct that holds a std::string. I've changed your example code to use the new cppstring struct. One important thing to note is that because the C code can only deal with a pointer to a cppstring, we need to create it on the heap in our C++ code and return the pointer to it. This means that we must provide the C users some way of freeing it when they're done, which I've also provided in the example.
Using this technique you can wrap the entirety of std::string behind a C API, allowing C users to use all of the functionality that std::string provides. I've provided an example of wrapping std::string::substr to show you how.
N.B. I haven't compiled nor tested this code and for the sake of simplicity I haven't included any of the relevant header files, etc. Nevertheless, it should be enough to get you started.
// C header
#ifdef __cplusplus
extern "C" {
#endif
typedef struct cppstring *cppstring_p;
cppstring_p exec(char *cmd, FILE *pipe);
void free_cppstring(cppstring_p cppstr);
/* example of wrapping std::string::substr for C users */
cppstring_p substr(cppstring_p str, int pos, int count);
#ifdef __cplusplus
}
#endif
// CPP source
struct cppstring {
std::string data;
cppstring(void) {}
cppstring(std::string const& s) : data(s) {}
};
cppstring_p exec(char *cmd, FILE *pipe) {
pipe = _popen(cmd, "r");
if (!pipe) return "ERROR";
char buffer[128];
auto result = new cppstring;
while(!feof(pipe)) {
if(fgets(buffer, 128, pipe) != NULL)
result->data += buffer;
}
_pclose(pipe);
return result;
}
void free_cppstring(cppstring_p cppstr) {
delete cppstr;
cppstr = nullptr;
}
cppstring_p substr(cppstring_p str, int pos, int count) {
assert(str);
return new cppstring(str->data.substr(pos, count));
}
You need to declare the function as extern "C" in the cpp file:
extern "C" char *exec(char* cmd, FILE* pipe) {
...
}
In the header/linker file you need to declare it's prototype with the keyword "extern", like so:
extern char *exec(char* cmd, FILE* pipe);
Also, are you sure you want to return a c++'s std::string to your C code?

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"
}

C/C++ replacement/redefinition rules?

I am not particularly new to C/C++ but today I discovered some things that I didn't expect.
This compiles in gcc:
/* test.c */
#include <stddef.h> // !
typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // NO ERROR
int
main(void)
{
typedef unsigned long int size_t; // NO ERROR
return 0;
}
This doesn't:
/* test.c */
#include <stddef.h>
typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // NO ERROR
int
main(void)
{
typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // ERROR
return 0;
}
This doesn't either:
/* test.h */ // ! header
typedef unsigned long int size_t;
typedef unsigned long int size_t; // ERROR
Similarly in g++ this compiles:
/* test.h */ // ! header
#include <cstddef>
inline void* operator new(size_t, void* p) throw() { return p; }
This doesn't:
/* test.h */ // ! header
#include <new> // !
inline void* operator new(size_t, void* p) throw() { return p; } // ERROR
This does:
/* test.cc */
#define _NEW
#include <new> // !
#include <iostream>
#include <cstdlib>
using std::cout;
using std::endl;
inline void* operator new(size_t size) throw() // NO ERROR EXPECTED
{
cout << "OPERATOR NEW CALLED" << endl;
return malloc(size);
}
inline void* operator new(size_t, void* p) throw() // NO ERROR
{
cout << "PLACEMENT NEW CALLED" << endl;
return p;
}
int main()
{
char *buffer[4];
int *i = new (buffer) int;
int *j = new int;
return 0;
}
(Replacing the standard new operator works in all of the above cases. Replacing the replacement new operator is illegal, I know.)
It is easy to see a pattern, but can somebody offer me a "standard" explanation?
Why can I do things in .c or .cc files that I can't in .h files (redefine old typedefs, replace functions that are illegal to replace)?
Thanks for the reply. I have omitted some code including the header guards. In the last .cc example, I HTML encoded << as & g t ; & g t ; by mistake and forgot to include cstdlib.
I have fixed the code so it compiles. However, another thing that I had omitted was #define _NEW, which proved crucial. Apparently in GNU the header guard of <new> defines _NEW, so my defining it here prevented the inclusion of the standard new header, so I the replacement worked
m#m:~/Desktop/Library$ ./a.out
PLACEMENT NEW CALLED
OPERATOR NEW CALLED
So yeah, the only thing that is left unexplained is how come I can re-typedef stuff in .c/.cc files multiple times but not in .h like so:
/* test.c */
#include <stddef.h>
typedef unsigned long int size_t; // NO ERROR
typedef unsigned long int size_t; // NO ERROR
int
main(void)
{
typedef unsigned long int size_t; // NO ERROR
return 0;
}
Not that I want to do that anyway, but just wondering.
EDIT: Thanks, that really answers all of it. Changing it to xyz does not allow multiple definitions in a given scope, which feels right. :)
The reason why I was doing these little tests is that I am writing a subset of C and C++ for a small operating system but since I am using the existing libraries without removing anything to assist me in the testing of mine, I was trying to figure out how to ensure that (1) my code is being called in the tests (e.g my placement new) and (2) that my code doesn't clash with the GNU libraries.
The answer to (1) now seems pretty obvious. I just #define the header guard macro from the standart X.h into my X.h :).
Using GCC 4.0.1 on MacOS X 10.4.11 (ancient - but so's the computer), the example with "test.h" works - or my adaptation of it does. It appears you can have as many (identical) global typedefs of 'size_t' as you like - I had 5 with the version in stddef.h.
The first typedef inside main is 'obviously' legal; it is a new scope and can define a new meaning for the name.
The C99 Rationale says:
In C89, a typedef could be redeclared in an inner block with a declaration that explicitly contained a type name. This rule avoided the ambiguity about whether to take the typedef as the type name or a candidate for redeclaration. In C99, implicit int declarations are not allowed, so this anbiguity [sic!] is not possible and the rule is no longer necessary.
Later on, discussing standard headers, it also says:
The C89 Committee decided to make library headers “idempotent,” that is, they should be
includable any number of times, and includable in any order. This requirement, which reflects
widespread existing practice, may necessitate some protective wrappers within the headers to
avoid, for instance, redefinitions of typedefs. To ensure that such protective wrapping can be
made to work, and to ensure proper scoping of typedefs, standard headers may only be included outside of any declaration.
Clearly, therefore, redefinitions of a typedef in a single scope (e.g. the file scope) is not allowed in general.
I think, therefore, that the multiple external redefinitions of size_t is probably either a feature of GCC or a bug - actually, a feature.
If you change size_t to xyz, you get many more errors.
I am not sure how the multiple typedefs compile in your case. Remember, headers don't compile by themselves, but in conjunction with an implementation class. Also, your headers lack header guards or a #pragma once directive. What options are you using?
As for placement new -- it is explicitly forbidden by the standard (18.5.1.3) -- so that won't work.
There is no pattern here -- except for redefinition of already declared symbols.
BTW: None of your .c or .cpp examples compile with Comeau.