CScope indexing with C++ and scoped function parameters - c++

I'm using cscope to create an index of some C++ source code. Mostly it works great but it has problems when parsing function names that have parameter types that are scoped (using '::'). For example:
void SomeClass::doSomethingAwesome( const std::string& input )
{
}
When I use the cscope interface to "Find this C symbol:" I get this:
File Function Line
0 doSomethingAwesome <global> 1 void SomeClass::doSomethingAwesome( const std::string& input )
The important bit is the global tag. It should be 'doSomethingAwesome'.
For another function without any scoped parameters e.g.
void SomeClass::doSomethingElse( int input )
I get this:
File Function Line
0 doSomethingElse doSomethingElse 1 void SomeClass::doSomethingElse( int input )
Note the Function field now matches the function name. I can now successfully search in cscope for other functions that call this function. I could not do that with doSomethingAwesome(). In addition any functions which are only called from doSomethingAwesome() will not show up as having been called by any function since doSomethingAwesome() has not been recognised as a function by cscope.
Am I doing something wrong? Or is this an issue in cscope's parsing of the function?

Related

Using callbacks in C++

I'm working on a project in C++, but at some point in the application it fails and generates a core dump. The application uses a couple of classes, which for the purposes here I'm concentrating on one of the classes, which I'm calling A, and is instantiated as object a. This has a large number of member functions, of which at the moment only a few are being used, but one of these generates a log to produce diagnostics to be used for debugging. I want to use this to find out why the application is failing.
The project is to put together code that invokes the various member functions, and although I have access to the source code and some limited documentation, none of the code can be changed, with all changes being in the code that makes use of the classes and invokes the member functions. The member function in question is:
void enable_log (log_callback callback, void * user_data = nullptr)
where the 1st argument callback contains the message and 2nd argument is optional. For now it can be set to nullptr, so would be invoked as:
a.enable_log(callback, nullptr);
From this documentation it's not at all clear what exactly callback is. However, in looking at the source code this is:
using log_callback = void (*)(const std::string& message, void* user_data);
in a header file, where log_callback is an alias for const std::string& if I understand this correctly.
I already have dummy classes on a platform using Visual Studio 2019 with some test member functions to simulate invoking the member functions on a remote Linux server, but I'm unable to find a way of making use of the member function above. I added the test member function to the dummy class as follows:
void enable_log(const std::string& callback, void* user_data = nullptr) {
callback = "ABCD";
}
which is supposed to generate a test string which is returned, such that in the real application this string will have diagnostic information that will be written to a file. However, the "=" is an error.
The idea is that in the main function an empty string will be declared, then enable_log() should populate this string, which can be printed out.
I've spent some time looking at various resources, including Stackoverflow, but I cannot find a way of returning a string with the information that can be printed out. I need a simple way to simulate this, and as I said above, I must not change the source code of the real member function, so the simulated member function has to produce a string in the same way. How is this done? Some advice would be appreciated.
Callback, in simple words, is some function that will be called later at some point. Example:
void callback_fn(int a);
using callback_t = (void)(*)(int a);
void some_func(callback_t);
You can use some_func() like so:
some_func(callback_fn);
Full example here: https://godbolt.org/z/ET3GhfYrv
For your usecase the parameters of the callback are slightly different. Here's how to read the syntax:
using log_callback = // this just creates an alias for whatever is on the right handside
void // the return type of the "callable" should be void
(*) // this tells us that it is a function pointer
(const std::string& message, void* user_data) // These are the arguments the callable takes. It is a "std::string" and a "void *"
To use this, just create a free function with the same signature:
void callable(const std::string &msg, void *userData = nullptr)
{
// msg is the data sent by the function. use it in whatever way
// you want.
std::cout << msg << '\n';
}
// Pass it to the enable_log
enable_log(callable);

implement a loggin function or macro can log date and function name

I want to write a logging function or macro which can accept other callback functions as parameter and run the callback function inside, log runtime and name.
But callback function may have different parameter type and number,and i don't want to pass callback function'name as parameter explicitly.
i try to use std::bind and std::function
void log(std::function<void()> callbackFunc){
//assuming all callbackFunc return type is void
struct timeval tmBegin, tmEnd;
gettimeofday(&tmBegin);
callbackFunc();
gettimeofday(&tmEnd);
//then write tmEnd - tmBegin to file
//but i dont know how to get callbackFunc's name}
void callbackFunc1(int);
void callbackFunc2(int ,char, string);
log(std::bind(callbackFunc1, 1));
log(std::bind(callbackFunc2, 2, 'c', "test"));
Aside,maybe callback function has different return type, is possible to implement a log function like this?
The names of functions (and variables, etc, etc) are lost when compiling. The compiler doesn't (really) know the name of a function. You can use __FUNCTION__ to get the name of the function you are in, but not useful in this case. You could perhaps do something with a macro that replaces bind, or the simple solution is to just pass in a string along with the function as an argument to log.
The macro solution is more complex, as you have to deal with variable arguments, but something like this would work):
#define LOG(f, ...) log(std::bind(f, __VA_ARGS__), #f)
and modify log to:
void log(std::function<void()> callbackFunc, const char* name)
Edit: Different return types could be dealt with by making log a templated function, and using the template as the type argument in the std::function return type:
template<typename RET>
void log(std::function<RET()> callbackFunc)
(I haven't tested this, but I believe it will work)
You could wrap the log call in a variadic macro (as you "guessed") to grab the parameter itself (function address) as well as it's name:
#define log(f, ...) _log(std::bind(f, __VA_ARGS__), #f)
void _log(std::function<void()> callbackFunc, const char *fName){
// ...
}
log(callbackFunc1, 1);

Dll Plug-in basic questions

For the last couple of days i've been learning C++ to make a dll plug-in for a program.
My objective is to get data(the Flight Plan's to be more precise) from the program and on a first phase save them to a text file(second phase will be connect them with python but for now it's just that).
So in my header file i imported a file with many classes and many functions(which is given by the plugin development guide). The class i'm interested in is the class CAircraftFlightPlan and it has some functions inside like this:
bool IsReceived(void) const;
//-----------------------------------------------------------------
// Return :
// true - if any kind of FL is received from the servers
// false - else
//-----------------------------------------------------------------
const char * GetOrigin ( void ) const ;
//-----------------------------------------------------------------
// Return :
// The origin airport.
//-----------------------------------------------------------------
int GetFinalAltitude ( void ) const ;
//-----------------------------------------------------------------
// Return :
// The final requested altitude.
//-----------------------------------------------------------------
I have many doubts about this, hope you can help:
1-what does it mean having "nameoffuction"(void) const? It receives nothing?how do i call these functions then
2-i do not understand this function "const char * GetOrigin ( void ) const ;",what does it want, a const or a char?
3-The comments below the functions tell that they return this or that. But how do they return that if the function is empty, it's just "int GetFinalAltitude(void) const"...
4-In the source file, i try to call one of the functions to write it to a txt file,how can i do this:
int airplane;
ofstream textfile;
textfile.open("FP.txt");
textfile<<int GetTrueAirspeed("MAH545"); //i know there's an error here, how do i solve it?
textfile.close();
I'm very sorry for asking these (noob i suppose) questions but they are way to specific to search for an answer online(i tried already)
Thank you for the help
Yes, it takes no arguments so you call it like so: nameoffunction()
This also takes no arguments so it is called as GetOrigin(). It returns a pointer to a const char.
As above, the functions take no arguments but do return values.
Delete the int in front of the function call. This should get rid of at least one error.
textfile<< GetTrueAirspeed("MAH545");

C++ fprintf over many functions to a single text file

I am having difficulty in printing to a text file from chosen locations within a large C++ code project.
Using C++ I am using a function X which is called multiple times.
This is called from a function Y
I wish to output the results of function X to a single text file and have done so by continously using declarations, fopen, fprintf, fclose set of functions - this works – albeit very slowly.
However, I only wish to print results to file when X is called from a specific area of the host function Y.
I am looking to do so, whilist being minimally invasive with the current code (i.e. I wouldn’t like to add another argument to the function X, nor would I like to declare global variables).
Is their a way a unique methods to effectively ‘tell’ the code and child functions when to start printing to file and when to stop.
(p.s. I have post-processed my results using VBA however this workaround is found to be inefficient).
Any ideas or code constructs would be most welcome!
swarm
Below is the child function X:
void `X`() {
FILE *f2 = NULL;
f2 = fopen("log.txt", "a");
// Calculate a result: `result`
fprintf(f2, "%.4e ", result);
fclose (f2);
}
Below is the main calling function Y:
void Y Y(){
for i=1:100{
X();
X();
X(); // <-- Wishing to print only this line to a text file
}
}
Since you're in C++, you can add an overload of X that takes an argument of when to do it, and not have to change any callers.
You have
void X(args);
Add
void X(args, bool doIt);
Then, move the code in the original X to the new one, checking doIt.
In the original X, call X(args, false)
Somehow the boolean state of whether to actually log has to be passed. Choices are: an argument, a global, an member variable (static or instance), a thread local variable, or a file.
Whatever you do. it will probably be logically equivalent to declaring a global variable. But you can ease the pain of this in various ways:
If X is a class member, you can declare the variable as a static member of X's class.
If X belongs to a namespace, your global variable can belong to that namespace.
You can declare it as a static variable, local to X's source file, and use a function in the source file to set its value.
And so on.
If you don't want to keep binary compliance, than you can also transform X function to structure/class with overloaded operator() - then add field or method specyfying if you should print it or not. - however this is quite similar to another global variable. Except overloading X, i doubt there is any other method that doesn't use globals or something similar.
How are you keeping your FILE* pointer between X calls? global? stativ variable in function?

How do I use a pointer to char from SWIG, in Perl?

I used SWIG to generate a Perl module for a C++ program. I have one function in the C++ code which returns a "char pointer". Now I dont know how to print or get the returned char pointer in Perl.
Sample C code:
char* result() {
return "i want to get this in perl";
}
I want to invoke this function "result" in Perl and print the string.
How to do that?
Regards,
Anandan
Depending on the complexity of the C++ interface, it may be easier, faster, and more maintainable to skip SWIG and write the XS code yourself. XS&C++ is a bit of an arcane art. That's why there is Mattia Barbon's excellent ExtUtils::XSpp module on CPAN. It make wrapping C++ easy (and almost fun).
The ExtUtils::XSpp distribution includes a very simple (and contrived) example of a class that has a string (char*) and an integer member. Here's what the cut-down interface file could look like:
// This will be used to generate the XS MODULE line
%module{Object::WithIntAndString};
// Associate a perl class with a C++ class
%name{Object::WithIntAndString} class IntAndString
{
// can be called in Perl as Object::WithIntAndString->new( ... );
IntAndString();
// Object::WithIntAndString->newIntAndString( ... );
// %name can be used to assign methods a different name in Perl
%name{newIntAndString} IntAndString( const char* str, int arg );
// standard DESTROY method
~IntAndString();
// Will be available from Perl given that the types appear in the typemap
int GetInt();
const char* GetString ();
// SetValue is polymorphic. We want separate methods in Perl
%name{SetString} void SetValue( const char* arg = NULL );
%name{SetInt} void SetValue( int arg );
};
Note that this still requires a valid XS typemap. It's really simple, so I won't add it here, but you can find it in the example distribution linked above.
You must have referred to the SWIG tutorial at www.swig.org/tutorial.html
Anyways, since you just want to invoke the function the C function from perl,
1. Type your interface file(having all the function declarations in the wrapper and the module sections).
2. Compile with swig and options.
3. Compile with gcc to create the objects.
4. Compile with gcc options to create the shared object.
5. run the program as follows:
perl
use moduleName;
$a = moduleName::result();
[NOTE: Look into the generated module file(.pm) for the correct funvtion prototype which points to the correct function in the wrapper file.]