I'm using VxWorks 6.9 and am trying to use some spyLib.h functions but I'm having issues finding what signature to expect given that the type is variadic.
in vxTypesOld.h I find my type: typedef int (*FUNCPTR) (...);
and in spyLib.h i have my function call : extern void spyReportCommon (FUNCPTR printRtn);
But what function parameters are expected for printRtn ? I guess a c-style string is one but I don't know if each line of the table is a string or if its an array of strings, or even one large string.
I can't start writing the function to parse data from the outputted data until I know in what form that data is passed into the function.
All I know for certain is that it returns an int (e.g. int parsePrint( ???? );)
Here is my attempt at reporting:
#include <vxworks.h>
#include <spyLib.h>
#include <usrLib.h>
int ParseSpy(const char * spyOutput); // this is a guess
void Startup()
{
//startup logic
// the compiler said and int param is expected but the .h had void
spyLibInit(1);
spyCommon(1,50, (FUNCPTR) &ParseSpy);
}
int ParseSpy(const char * spyOutput){} // this is a guess
I'm getting an unexpected compiler error: 'spyCommon' was not declared in scope
but as you can see spyLib.h was included so I'm a bit confused by this.
That looks like a bad design. The print function cannot print if it does not know what the parameters are. At least one parameter is needed to specify what the rest of the parameters are.
Looking at the source and searching for "printRtn" I see that all calls to the print function are expecting a printf like function where the first parameter is a format string. Your function should better be written as
int ParseSpy(const char * spyOutput, ...);
Regarding the missing spyCommon you could try to let VxWorks write the preprocessor output to a file to check what the compiler sees. Maybe you are getting the wrong spylib.h file or something it that file is hidden by #if.
Related
I have run into issues (runs on Intel, odd run results on ARM) when using this typedef:
typedef char IPString[17];
...
IPString ipStr;
extractIPfromURL("https://192.168.0.1:80", ipStr);
NOTE: I CANNOT use std::string, because code needs to compile on GCC and IAR. While IAR does support std::string the rule is not to use it.
If extractIPfromURL signature is:
void extractIPfromURL(const char* url, IPString *ipStr);
and implementation uses:
const char* ep;
...
strncpy(ipStr[0], &ep[start], end-start+1);
*ipStr[end+1] = '\0';
caller for pointer:
IPString ipStr;
extractIPfromURL("https://192.168.0.1:80", &ipStr);
everything works.
But if I was to use signature:
void extractIPfromURL(const char* url, IPString &ipStr);
and implementation:
const char* ep;
...
strncpy(&ipStr[0], &ep[start], end-start+1);
ipStr[end+1] = '\0';
caller for reference:
IPString ipStr;
extractIPfromURL("https://192.168.0.1:80", ipStr);
The code on ARM appears to behave as I rewrote some of the stack and my loop that is supposed to iterate over 2 items iterates over 2 items forever like: 0, 1, 0, 1, 0, 1, etc.
I tried an explicit reference declaration:
typedef char (&IPStringRef)[17];
but got the same loop on ARM (Raspberry PI).
I am sure I am not using typedef correctly in here, but I don't understand what exactly is it that I am doing wrong.
Your question is rather unclear. Part-way down the question you say you say "If [I do this] everything works". So the obvious solution is: do that.
I am assuming that you are asking why the code you posted bits of at the start of the question doesn't work.
Assuming that code is:
typedef char IPString[17];
void extractIPfromURL(const char* url, IPString *ipStr);
void some_function(void)
{
IPString ipStr;
extractIPfromURL("https://192.168.0.1:80", ipStr);
}
You should get a compilation error. If you don't see an error message then it is time to adjust the flags you pass to the compiler. The code is a constraint violation because the argument type char * does not match the parameter type char (*)[17].
The argument should match the parameter type. You have (at least) three different options for the argument: IPstring, IPstring *, IPstring &. They will all work , so long as you pass the matching argument form, and you use the parameter correctly inside the function (and your code doesn't contain any other bugs of course).
If you are still having trouble then try to post a MCVE. At the moment it is anybody's guess what is causing the problem you see on ARM since you only posted bits and pieces.
You could also consider not using the typedef at all.
This code is suspicious:
strncpy(&ipStr[0], &ep[start], end-start+1);
ipStr[end+1] = '\0';
If start is not zero then you are placing the \0 some distance past the end of where you actually finished copying characters. I would recommend avoiding strncpy entirely as it is relatively difficult both to use correctly, and to verify correct use of when you are reviewing code later.
I will use a pseudo example here, though I have noticed this behaviour in several APIs, like sqlite3 or windows.
Say a function is declared like so:
void Fu(some_identifier **ppBar);
and I do this in my code:
some_identifier **ppFubar;
fu(ppFubar);
It is my understanding that this would work and indeed it does in my own functions. Yet my program crashes after a buffer overflow when I do this with some APIs.
If I do this:
some_identifier *pFubar;
fu(&pFubar);
everything is fine.
Do ppFubar and &pFubar not evaluate to the exact same thing?
EDIT:
A concrete example would be (fourth argument):
int sqlite3_prepare(
sqlite3 *db, /* Database handle */
const char *zSql, /* SQL statement, UTF-8 encoded */
int nByte, /* Maximum length of zSql in bytes. */
sqlite3_stmt **ppStmt, /* OUT: Statement handle */
const char **pzTail /* OUT: Pointer to unused portion of zSql */
);
Your understanding is wrong.
If a function takes a some_identifier **ppFubar; parameter it is probably going to do something related to a some_identifier object somewhere inside its function body.
If you call it with some_identifier **ppFubar; you are giving it an uninitialized pointer, i.e. a pointer to garbage. If the function does anything with it (for example, it dereferences it, either once or twice), you are incurring in undefined behaviour (most likely, it will crash).
Pass a correctly initialized pointer to the function.
I mean strings like "(%d%%%d) some text %s , %d%% %x %o %#x %#o \n". The printf family of functions somehow know how many args they would need from this string so separate argument for it is not needed. Is this functionality provided in c/c++ in terms of a separate function so I could write my own printf-like functions ? (yes I put these percents intentionally to accent how complicated it could get, so it is not simple counting of percent characters)
The problem with printf family is that it is not safe, and it doesn't really know or care how many format elements are there in string or in argument list.
printf family uses something called "variadic functions"; only one parameter is named (format string) and others are taken from the stack, without respecting their type or size - their type is deduced from format string, which makes it type-unsafe, and finds how many arguments to use by iterating over the string and finding all formatting specifiers, which makes it argument-number-unsafe. You can write variadic functions; syntax is
void foo(...);
and later you can use those macros and types, although if you are using C++, you should use C++11's variadic templates instead of C variadic functions, as variadic templates are type safe - you don't loose type information anywhere, and with universal references (but not quite thanks them) they are more powerful than variadic functions.
No, there is no standard library function for parsing printf-style format strings. If you want to write your own string formatting function, then I strongly recommend against following the printf example. It's inherently unsafe for the reasons mentioned in the others answers. It also has problems with localization since word order changes in some languages. Personally, I would write a type-safe function using templates and copying the .NET style of format strings. (Actually, I did do that--it's a lot of work but also fun.)
the printf family of functions only knows about one parameter, the first one...
It basically scans the string and each time it encounters a format specifier that it understands it pulls then next argument of that size from the argument list... this is an easily corruptible behavior.
imagine:
printf("%i",someInt); // fine
printf("%i",someLong); // depending on endianness and sized
// of those types could be the high or low 32 bits(probably)
printf("%i %i",someInt); // depending on abi could crash, read a int sized chunk
// of stack, or a register that would correspond to that
// parameter.
so inherently not safe..
you should pay attention to warnings and when writing portable code do things like:
size_t t = 5; //can be 32 or 64 bit depending on arch.
printf("%ull",(unsigned long long)t);
Edit. I guess I only half answered the question...
you can define your own variadic functions, the following adds count number of params and returns the result.
int sumList(int count, ...);
int main(int argc, const char * argv[])
{
printf("the answer is: %i",sumList(4,1,2,3,4));
return 0;
}
int sumList(int count, ...)
{
va_list args;
va_start(args, count);
int sum = 0;
for (int i = 0; i<count; i++) {
sum += va_arg(args, int);
}
va_end(args);
return sum;
}
I am trying to get the Aruco AR library working by trying out the simple test in my code.
For some reason I cannot get the call to detect() to work. My code is as follows:
cv::Mat image(480,640,CV_8UC3, mimFrameRGB.data());
MarkerDetector mDetector;
std::vector<Marker> markers;
CameraParameters cParams();
float markerSize = 0.1f;
mDetector.detect(image,markers,cParams,markerSize);
The compiler complains that there is no overloaded function that matches my input parameters. Specifically that parameter 3 should be of type cv::Mat.
Looking at the header file for the MarkerDetector, the following two method calls are found:
void detect(const cv::Mat &input,std::vector<Marker> &detectedMarkers,cv::Mat camMatrix=cv::Mat(),cv::Mat distCoeff=cv::Mat(),float markerSizeMeters=-1) throw (cv::Exception);
void detect(const cv::Mat &input,std::vector<Marker> &detectedMarkers, CameraParameters camParams,float markerSizeMeters=-1) throw (cv::Exception);
I am trying to call the second one, however it chooses the first one and gives me a compile error. What is going wrong? are my input parameters not matching either case?
I think the issue is this line:
CameraParameters cParams();
This does not declare a variable of type CameraParameters, but instead is a function prototype for a function called cParams that takes no parameters and returns a CameraParameters. This is an extremely annoying part of the C++ language, since the code is legal but doesn't do what you want.
Because cParams is actually a function prototype and not a variable declaration, the C++ overload resolution mechanism is getting confused about the types of the arguments and is failing to correctly select the oveload you'd like. Removing the parentheses on this line and having it just read
CameraParameters cParams;
should fix this problem.
Hope this helps!
The problem is; when you declare cParams like CameraParameters cParams(); you are actually declaring a function named cParams which returna a CameraParameters. It should be CameraParameters cParams; (Remove paranthesis).
I'm betting it's because:
CameraParameters cParams();
which actually declares a function cParams taking no arguments and returning a CameraParameters.
So when you call the method and pass it cParams, it interprets that as a function pointer, which is probably why it chooses the first variant.
Replace it with:
CameraParameters cParams;
I have to classes, an Executer with these methods:
Executer()
struct Execute(string s)
Lookup(string name, int module, int num, ...)
and a Parser:
Parser()
struct Parse(string s)
The Exectuers Execute method calls the Parsers Parse method. The Parser then chucks the string into smaller bits (it explodes the string on the ;-sign) and returns a struct to the Execute method. This struct it uses to call the Lookup method.
The struct that the Parse returns holds some standard information:
An command name
A senderId (a username, a mac address and a password)
A variable number of arguments
And that is my problem. The Lookup method take variable arguments, but how do I handle the the hand over of these variable arguments by the struct? Im not an expert in C and C++. Should I mass the two classes togheter? So the Parser method could call the Execute method, sparing the struct away.
Or maybe there is a way of parsing an unknown variable of arguments at runtime? By some sort of array?
EDIT
I cant use the STL library from C++. I only use the C++ class and virtual feature. Im writing to an compiler where Im restricted to use almost all of the C libraries + the magic skills of C++ (virtual and class). SOory for not telling that right away.
EDIT 2
Im writing code to an embedded system and thereby using avr-gcc to compile my code. Thats why I cant use STL. The avr-gcc doesnt support this.
Use std::vector<> or a simular container that can hold an arbitrary number of entries.
struct {
std::string commandName;
sender_t senderId;
std::vector<arg_t> arguments;
};
Edit: oh, you can't use std::vector. In that case: use an array and store the length:
struct {
const char* commandName;
sender_t senderId;
int argumentCount;
int maxArgumentCount; // you might not need this
arg_t* arguments; // pointer to array of (at least) argumentCount elements.
};
Use malloc() or new() to create the array for the arguments.
I would suggest to wrap the argumentCount, maxArgumentCount and arguments in a separate class, which can handle the malloc/new and free/delete as well. This will make it easier to prevent memory leaks.
In the end, you'll have written your own vector_of_arg_t class, so maybe have a look at some basic vector implementation. There must be tutorials on that on the web.
You could declare your Lookup method as follows:
void Lookup(string name, int module, int num, std::vector<std::string> &args);
By storing the variable arguments in an args array, you can have as many as you want.
See
Q: How can I write a function which takes a variable number of arguments and passes them to some other function (which takes a variable number of arguments)?
A: In general, you cannot. Ideally, you should provide a version of that other function which accepts a va_list pointer.
Suppose you want to write a faterror function which will print a fatal error message, then exit. You might like to write it in terms of the error function of question 15.5:
void faterror(const char *fmt, ...)
{
error(fmt, what goes here? );
exit(EXIT_FAILURE);
}
but it's not obvious how to hand faterror's arguments off to error.
<snip>
Read on at
http://c-faq.com/varargs/handoff.html