I'm trying to build a project 8051 in Keil IDE.
I have a definition to print information for purposes debug program as following:
#define LOGI(fmt, ...) printf("[I] %s:%u: "fmt, __FILE__, __LINE__, ##__VA_ARGS__)
But there are errors:
log.h(18): error C301: identifier expected
log.h(18): error C301: identifier expected
log.h(18): error C304: bad macro parameter list
Please help me fix this code, thank you.
According to the documentation, Keil C51 is based on C90. So it does not support __VA_ARGS__ that is a C99 addition.
However, you can work around this for example by this trick. Use a parenthesized argument.
#define LOGI(args) \
do { \
printf("[I] %s:%u: ", __FILE__, __LINE__); \
printf args; \
} while (0)
void f(void) {
LOGI(("address of f() = %p\n", f));
}
Another possible solution is to provide an own function with a variable number of arguments, see the example in the documentation. This is a cleaner way because you can use this function without a "hick-up" when reading the source code because of the double parentheses. But be aware that these arguments are not placed in registers, and more memory on stack and in code is used.
#include <stdio.h>
#include <stdarg.h>
void logi(const char* filename, int line, char *fmt, ...) {
va_list arg_ptr;
va_start(arg_ptr, fmt);
printf("[I] %s:%u: ", filename, line);
vprintf(fmt, arg_ptr);
va_end(arg_ptr);
}
void f(void) {
logi(__FILE__, __LINE__, "Hello %u %u", 1 , 2);
}
Note: You might want to switch to another compiler, which supports some newer standard than a 30 years old one.
Related
So I am having an issue using basename for one of my programming assignments for school
I have tried getting a simplier version of it working -- I got it working however, still confused exactly what I am supposed to do in this case
// $Id: util.cpp,v 1.1 2016-06-14 18:19:17-07 - - $
#include <libgen.h>
#include <cstring>
using namespace std;
#include "util.h"
ydc_exn::ydc_exn (const string& what): runtime_error (what) {
}
string exec::execname_; // Must be initialized from main().
int exec::status_ = EXIT_SUCCESS;
void exec::execname (const string& argv0) {
execname_ = basename (argv0.c_str());
cout << boolalpha;
cerr << boolalpha;
DEBUGF ('Y', "execname = " << execname_);
}
void exec::status (int new_status) {
new_status &= 0xFF;
if (status_ < new_status) status_ = new_status;
}
ostream& note() {
return cerr << exec::execname() << ": ";
}
ostream& error() {
exec::status (EXIT_FAILURE);
return note();
}
Just trying to get the code to compile --- my error message in c++ is:
'
util.cpp:15:16: error: no matching function for call to 'basename'
execname_ = basename (argv0.c_str());
^~~~~~~~
/usr/include/libgen.h:40:7: note: candidate function not viable: 1st argument ('const std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char>
>::value_type *' (aka 'const char *')) would lose const qualifier
char *basename(char *);
^
1 error generated.
make: *** [util.o] Error 1'
basename takes char* as argument, which is not const, meaning the function is allowed to modify the value.
const string& argv0 is const, meaning the value of argv0 must not be modified.
Thus you are not allowed to call basename with argv0.c_str() as parameter, as that would violate the const qualifier.
The error message is clear: 1st argument ... would lose const qualifier.
So either change argv0 to not be const (probably not a good idea), or change basename to take a const char* parameter (probably the better idea), or change basename to work with std::string instead of char* like the rest of your code (probably the best idea).
So apparently basename is a unix function that you cannot change. (Thanks Nevin!) From the manpage:
Both dirname() and basename() may modify the contents of path, so it may be desirable to pass a copy when calling one of these functions.
In that case I recommend creating a copy of argv0. The simplest way of doing this would be to change the signature of execname to this:
void exec::execname(std::string argv0)
I think that your central problem is including libgen.h as well as cstring. If you look at the prototypes for basename in those files, they're different. If you're building this on linux, you'll see a comment in the libgen.h version which should be enlightening.
https://pubs.opengroup.org/onlinepubs/9699919799/utilities/basename.html and
https://linux.die.net/man/3/basename are useful here too.
I suggest removing the #include <libgen.h> and trying again.
I am trying to run sample rsa/dsa code using libtomcrypt.
I have installed LibTomMath first as make install, as a result following files are created.
/usr/lib/libtommath.a
/usr/include/tommath.h
After that I installed libtomcrypt with LibTomMath as external library
CFLAGS="-DLTM_DESC -DUSE_LTM -I/usr/include" EXTRALIBS="/usr/lib/libtommath.a " make install
As a result following file is created
/usr/lib/libtomcrypt.a
I am not getting any error while running following command
CFLAGS="-DLTM_DESC -DUSE_LTM -I/usr/include" EXTRALIBS="/usr/lib/libtommath.a " make test
I have gone through this document libtomcrypt_installation and libtomcrypt_resolved to successfully compile using
gcc -DLTM_DESC rsa_make_key_example.c -o rsa -ltomcrypt
or
gcc rsa_make_key_example.c -o rsa -ltomcrypt
no compile error. However when I try to run, I got following error.
./rsa
LTC_ARGCHK 'ltc_mp.name != NULL' failure on line 34 of file src/pk/rsa/rsa_make_key.c
Aborted
Here is my sample rsa code
#include <tomcrypt.h>
#include <stdio.h>
int main(void) {
# ifdef USE_LTM
ltc_mp = ltm_desc;
# elif defined (USE_TFM)
ltc_mp = tfm_desc;
# endif
rsa_key key;
int err;
register_prng(&sprng_desc);
if ((err = rsa_make_key(NULL, find_prng("sprng"), 1024/8, 65537,&key)) != CRYPT_OK) {
printf("make_key error: %s\n", error_to_string(err));
return -1;
}
/* use the key ... */
return 0;
}
Here is my sample dsa code
#include <tomcrypt.h>
#include <stdio.h>
int main(void) {
# ifdef USE_LTM
ltc_mp = ltm_desc;
# elif defined (USE_TFM)
ltc_mp = tfm_desc;
# endif
int err;
register_prng(&sprng_desc);
dsa_key key;
if ((err = dsa_make_key(NULL, find_prng("sprng"), 20, 128,&key)) != CRYPT_OK) {
printf("make_key error: %s\n", error_to_string(err));
return -1;
}
/* use the key ... */
return 0;
}
Here is how I have compiled it successfully,
gcc dsa_make_key_example.c -o dsa -ltomcrypt
When I try to run the code , I am getting following error .
./dsa
segmentation fault
EDIT 1:
I investigated further and found the reason for segmentation fault
#ifdef LTC_MPI
#include <stdarg.h>
int ltc_init_multi(void **a, ...)
{
...
...
if (mp_init(cur) != CRYPT_OK) ---> This line causes segmentation fault
Where am I making mistakes ? How to resolve this problem to run these programs successfully?
I am using linux , gcc. Any help/link will be highly appreciated. Thanks in advance.
It's been a year or so since this was asked, but I have some component of an answer, and a workaround.
The reason mp_init fails is that the "math_descriptor" is uninitialized. mp_init is a defined as
#define mp_init(a) ltc_mp.init(a)
where ltc_mp is a global struct (of type ltc_math_descriptor) that holds pointers to the math routines.
There are several implementations of the math routines available, and a user can choose which they want. For whatever reason, there does not seem to be a default math implementation chosen for certain builds of libtomcrypt. Thus, the init member of ltc_mp is null, and we get the SIGSEGV.
Here is a manual workaround:
You can make your desired ltc_math_descriptor struct available to your main() routine by #defineing one of
LTM_DESC -- built-in math lib
TFM_DESC -- an external fast math package
GMP_DESC -- presumably a GNU MultiPrecision implementation?
Before #include <tomcrypt.h> (or by using -D on the command-line).
Whichever you choose, a corresponding object will be declared:
extern const ltc_math_descriptor ltm_desc;
extern const ltc_math_descriptor tfm_desc;
extern const ltc_math_descriptor gmp_desc;
To use it, manually copy it to the global math descriptor:
E.g., in my case, for the local math imlpementation,
ltc_mp = ltm_desc;
Now libtomcrypt works.
I have following code:
int _tmain(int argc, char** argv) {
bool g_graphics = true;
palPhysics * pp = 0;
#ifndef PAL_STATIC
PF -> LoadPALfromDLL();
#endif
char a[] = "Bullet";
std::string aa;
aa = std::string(argv[1]);
//PF->SelectEngine("Bullet");
DebugBreak();
PF -> SelectEngine(argv[1]);
//PF->SelectEngine(aa);
//debug
// assert(false);
pp = PF -> CreatePhysics();
}
I am trying to read in the command line argument no. 1 in this line:
PF->SelectEngine(argv[1]);
However, I only get the first letter of the argument. I have also tried changing
int _tmain(int argc, char** argv)
to
int _tmain(int argc, TCHAR** argv), but then I get
error:
error C2664: 'palFactory::SelectEngine' : cannot convert parameter 1 from 'TCHAR *' to 'const PAL_STRING &'
PAL_STRING is just a std::string.
This might be a simple one, but I am not sure how to convert TCHAR to std::string, especially since TCHAR is something else depending on compiler /environment settings. Is anyone aware of an easy way to get the command-line arguments to work, such that I don't need to convert anything myself, i..e maybe by changing the tmain function?
Thanks!
C
Update: example of invoking on command line:
Yep. so the way I invoke this on command line is:
progname.exe arg1 arg2,
where arg1 is a physics engine I am trying to load, and arg2 is a dae(physics file with physics info), so I go, specifically:
progname.exe Bullet E:/a.dae
Stepping into the line "PF->SelectEngine(argv[1]);" gives the following code:
bool palFactory::SelectEngine(const PAL_STRING& name) {
#ifdef INTERNAL_DEBUG
printf("palFactory::SelectEngine: this = %p\n", this);
#endif
SetActiveGroup(name); // also calls RebuildRegistry
return isClassRegistered("palPhysics");
}
, in this case, when debugging, I can see that const PAL_STRING& name, i.e. the string, is just "B", instead of what I would expect it to be, which is "Bullet", my command line argument I have passed in the command line.
I've been plauged by this problem for years. The only solution I've been able to find is to NOT USE Visual Studio. I've had to fall back to using other compilers when I must be able to process command-line args. Specifically, I've been using the Digital Mars compiler successfully. It handles the command-line args correctly. I use the VS environment for intellisense and debugging, then compile with DMC to deploy.
---edit below---
Turns out, I just wasn't asking the right question. I finally asked the right question, and got the right answer! See link below.
What is the difference between _tmain() and main() in C++?
This question is specific to Visual C++ (you may assume Visual C++ 2005 and later).
I would like to create glue code for a program from unixoid systems (FreeBSD in particular) in order build and run on Win32 with a minimum of changes to the original .c file. Now, most of this is straightforward, but now I ran into an issue. I am using the tchar.h header and TCHAR/_TCHAR and need to create glue code for the err and errx calls (see err(3)) in the original code. Bear with me, even if you don't agree that code using tchar.h should still be written.
The calls to err and errx take roughly two forms, and this is where the problem occurs:
err(1, "some string with %d format specifiers and %s such", ...)
/* or */
err(1, NULL, ...)
The latter would output the error stored in errno (using strerror).
Now, the question is, is there any way to write a generic macro that can take both NULL and a string literal? I do not have to (and will not) care about variables getting passed as the second parameter, only NULL and literal strings.
Of course my naive initial approach didn't account for fmt passed as NULL (using variadic macros!):
#define err(eval, fmt, ...) my_err(eval, _T(fmt), __VA_ARGS__)
Right now I don't have any ideas how to achieve this with macros, because it would require a kind of mix of compile-time and runtime conditionals that I cannot imagine at the moment. So I am looking for an authoritative answer whether this is conceivable at all or not.
The method I am resorting to right now - lacking a better approach - is to write a wrapper function that accepts, just like err and errx, a (const) char * and then converting that to wchar_t * if compiled with _UNICODE defined. This should work, assuming that the caller passes a _TCHAR* string for the variable arguments after the fmt (which is a sane assumption in my context). Otherwise I'd also have to convert %s to %hs inside the format string, to handle "ANSI" strings, as MS calls them.
Here's one solution:
#define _WIN32_WINNT 0x0502
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
#ifdef _UNICODE
#define LNULL NULL
#define fn(x) myfn(L ## x)
#else
#define fn(x) myfn(x)
#endif
void myfn(TCHAR * str)
{
if (str == NULL) _tprintf(_T("<NULL>")); else _tprintf(str);
_tprintf(_T("\n"));
}
int main(int argc, char ** argv)
{
fn("hello");
fn(NULL);
return 0;
}
I'm quite new to Visual C++ so this might be a 'schoolboy' error, but the following code is not executing as I'd expected:
#include "stdafx.h"
#include <string.h>
int _tmain(int argc, _TCHAR* argv[])
{
if (strcmp((char*)argv[1], "--help") == 0)
{
printf("This is the help message."); //Won't execute
}
return 0;
}
The executable, named Test.exe is launched as follows
Test.exe --help
I was expecting the message This is the help message. but I'm not seeing it - debugging reveals that the if condition comes out as -1 and not 0 as I'd expect. What am I doing wrong?
OK, I've figured out what's going on. The argv[] array is declared as TCHAR*, which is a macro that adjust the type based on whether or not Unicode has been enabled for the project (wchat_t if it is or char if it is not). The strcmp function, which I was trying to use, is the non-Unicode string comparison while wcscmp is the Unicode equivalent. The _tcscmp function uses the appropriate string comparison function depending on the Unicode setting. If I replace strcmp with _tcscmp, problem solved!
#include "stdafx.h"
#include <string.h>
int _tmain(int argc, _TCHAR* argv[])
{
if (_tcscmp(argv[1], _T("--help")) == 0)
{
printf("This is the help message."); //Will execute :)
}
return 0;
}
The _T function converts the argument to Unicode, if Unicode is enabled.
See also: Is it advisable to use strcmp or _tcscmp for comparing strings in Unicode versions?