I'm trying to create a cross-platform program. I just created a class and made a function which gets the path of the current user. I wanted to use that path later. But somehow I get these errors :
"/usr/include/x86_64-linux-gnu/sys/stat.h:-1: In member function 'void FileManager::p_getfilepath()':"
"/usr/include/x86_64-linux-gnu/sys/stat.h:105: error: expected unqualified-id before string constant"
"/home/david/VocabularyTrainer/filemanager.cpp:31: error: expected '}' at end of input"
btw the 31th line is the last line here in this code :
void FileManager::p_getfilepath()
{
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/stat.h>
struct passwd *p;
uid_t uid;
if ((p = getpwuid(uid = geteuid())) == NULL)
{
QMessageBox* mb;
mb->setText("");
mb->exec();
delete mb;
}
else
{
filepath = p->pw_dir;
}
#endif
}
Anyone knows what's wrong? I'm on linux mint.
By including your headers inside your class functions, you're making everything in the header a part of the function.
#ifdef Q_OS_WIN32
#include <windows.h>
#endif
#ifdef Q_OS_LINUX
#include <sys/stat.h>
#endif
void FileManager::p_getfilepath()
{
#ifdef Q_OS_LINUX
struct passwd *p;
uid_t uid;
if ((p = getpwuid(uid = geteuid())) == NULL)
{
QMessageBox* mb;
mb->setText("");
mb->exec();
delete mb;
}
else
{
filepath = p->pw_dir;
}
#endif
}
Related
I wrote a c-code designed for linux platform.
Now, I want to make it cross-platform so to use in Windows as-well.
In my code, I dlopen an so file and utilize the functions inside it.
Below is how my code looks like. But I just found out that in windows, the way to load and use dynamic library is quite different.
void *mydynlib
mydynlib= dlopen("/libpath/dynlib.so",RTLD_LAZY);
void (*dynfunc1)() = dlsym(mydynlib,"dynfunc1");
void (*dynfunc2)(char*, char*, double) = dlsym(mydynlib,"dynfunc2");
int (*dynfunc3)() = dlsym(mydynlib,"dynfunc3");
From what I found, I need to use LoadLibrary & GetProcAddress instead of dlopen & dlsym. However, I do not know how to convert above line for windows using those. I've tried to search some examples for hours but couldn't find exact solution. If someone had this kind of experience, please give me a tip.
Excuse me if this is too obvious problem. I'm quite new to C. I usually write my program in python.
Once in my youth I created something like this:
/* dlfcn.h */
#ifndef DLFCN_H
#define DLFCN_H
#define RTLD_GLOBAL 0x100 /* do not hide entries in this module */
#define RTLD_LOCAL 0x000 /* hide entries in this module */
#define RTLD_LAZY 0x000 /* accept unresolved externs */
#define RTLD_NOW 0x001 /* abort if module has unresolved externs */
/*
How to call in Windows:
void *h = dlopen ("path\\library.dll", flags)
void (*fun)() = dlsym (h, "entry")
*/
#ifdef __cplusplus
extern "C" {
#endif
void *dlopen (const char *filename, int flag);
int dlclose (void *handle);
void *dlsym (void *handle, const char *name);
const char *dlerror (void);
#ifdef __cplusplus
}
#endif
#endif
and dlfcn.c:
/* dlfcn.c */
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windows.h>
static struct {
long lasterror;
const char *err_rutin;
} var = {
0,
NULL
};
void *dlopen (const char *filename, int flags)
{
HINSTANCE hInst;
hInst= LoadLibrary (filename);
if (hInst==NULL) {
var.lasterror = GetLastError ();
var.err_rutin = "dlopen";
}
return hInst;
}
int dlclose (void *handle)
{
BOOL ok;
int rc= 0;
ok= FreeLibrary ((HINSTANCE)handle);
if (! ok) {
var.lasterror = GetLastError ();
var.err_rutin = "dlclose";
rc= -1;
}
return rc;
}
void *dlsym (void *handle, const char *name)
{
FARPROC fp;
fp= GetProcAddress ((HINSTANCE)handle, name);
if (!fp) {
var.lasterror = GetLastError ();
var.err_rutin = "dlsym";
}
return (void *)(intptr_t)fp;
}
const char *dlerror (void)
{
static char errstr [88];
if (var.lasterror) {
sprintf (errstr, "%s error #%ld", var.err_rutin, var.lasterror);
return errstr;
} else {
return NULL;
}
}
You could use a set of macros that change depending on the OS you're on:
#ifdef __linux__
#define LIBTYPE void*
#define OPENLIB(libname) dlopen((libname), RTLD_LAZY)
#define LIBFUNC(lib, fn) dlsym((lib), (fn))
#elif defined(WINVER)
#define LIBTYPE HINSTANCE
#define OPENLIB(libname) LoadLibraryW(L ## libname)
#define LIBFUNC(lib, fn) GetProcAddress((lib), (fn))
#endif
This is a class I'm doing to organize every memory block I allocate using malloc/calloc, so I can easily dispose of them later. The following is the definition of this class:
#include "memmanager.h"
std::vector<void*> MemoryManager::GarbageCollector(0);
void MemoryManager::AddToGC(void* myThing)
{
if(__DEBUG__MODE__)
MainDebugger.Log("Adding 1 element to GC: %p", "Info", myThing);
MemoryManager::GarbageCollector.push_back(myThing);
return;
}
void MemoryManager::MultiAddToGC(int args, void* myThing, ...)
{
if(args < 1)
return;
#ifdef _DEBUG
MainDebugger.Log("Adding %i element to GC", "Info", args);
#endif
va_list chrstr;
va_start(chrstr, args);
for(int x = 0; x < args; x++)
MemoryManager::GarbageCollector.push_back(va_arg(chrstr, void*));
va_end(chrstr);
return;
}
void MemoryManager::Flush()
{
int lasterror = 0;
#ifdef _DEBUG
MainDebugger.Log("Call to MemoryManager::Flush() with %i items in the GC", "Info", MemoryManager::GarbageCollector.size());
#endif
for(unsigned int x = 0; x < MemoryManager::GarbageCollector.size(); x++)
{
errno = lasterror = 0;
free(GarbageCollector[x]);
lasterror = errno;
if(lasterror > 0)
MainDebugger.Log("MemoryManager::Flush() Error: %s (%i : %p)", "Error", strerror(lasterror), x, GarbageCollector[x]);
}
GarbageCollector.clear();
return;
}
The problem seems to be with the function "MultiAddToGC". When I do this in my main file:
MemoryManager::MultiAddToGC(3,tst,mfile,testfile);
MemoryManager::Flush();
It works fine if I'm in Debug mode (I'm doing this in VC++ 2010). But if I change to Release mode, it gives me an error inside MemoryManager::Flush() while calling the free() function (something about the stack being corrupted). I can continue, if I continue, I get the following in my log:
15:12:26 f 00 (0 fps) | Error > MemoryManager::Flush() Error: Invalid
argument (2 : 00D44784)
However, if I do this:
MemoryManager::AddToGC(tst);
MemoryManager::AddToGC(mfile);
MemoryManager::AddToGC(testfile);
MemoryManager::Flush();
It works both in Debug, and release. No errors. So I'm assuming the error is in MultiAddToGC(), but I can't find it. The following code is the header, "memmanager.h":
#ifndef __MEMMANAGER_H__
#define __MEMMANAGER_H__
#include <vector>
#include <malloc.h>
#include <stdarg.h>
#include "..\core.h"
#include "..\DEBUGGER\debugger.h"
extern bool __DEBUG__MODE__;
extern GameDebugger MainDebugger;
class MemoryManager {
public:
static void MemoryManager::AddToGC(void*);
static void MemoryManager::MultiAddToGC(int, void*,...);
static void MemoryManager::Flush();
private:
static std::vector<void*> GarbageCollector;
protected:
};
#endif
Any help/tips/advise is wellcome.
In va_start(chrstr, args);, the second parameter should be the last named parameter, so myThing (but you probably want to remove myThing in fact).
but I would write
template <typename...Ts>
void MemoryManager::MultiAddToGC(Ts*... myThings)
{
if(sizeof...(myThings) < 1)
return;
#ifdef _DEBUG
MainDebugger.Log("Adding %i elements to GC", "Info", sizeof...(myThings));
#endif
int dummy[] = {(MemoryManager::GarbageCollector.push_back(myThings), 0)...};
(void) dummy; // avoid warning for unused variable
}
or simply
void MemoryManager::MultiAddToGC(const std::initializer_list<void*>& myThings)
{
if(myThings.size() < 1)
return;
#ifdef _DEBUG
MainDebugger.Log("Adding %i elements to GC", "Info", myThings.size());
#endif
MemoryManager::GarbageCollector.insert(MemoryManager::GarbageCollector.begin(),
myThings.begin(), myThings.end());
}
How can I get the actual "username" without using the environment (getenv, ...) in a program? Environment is C/C++ with Linux.
The function getlogin_r() defined in unistd.h returns the username. See man getlogin_r for more information.
Its signature is:
int getlogin_r(char *buf, size_t bufsize);
Needless to say, this function can just as easily be called in C or C++.
From http://www.unix.com/programming/21041-getting-username-c-program-unix.html :
/* whoami.c */
#define _PROGRAM_NAME "whoami"
#include <stdlib.h>
#include <pwd.h>
#include <stdio.h>
int main(int argc, char *argv[])
{
register struct passwd *pw;
register uid_t uid;
int c;
uid = geteuid ();
pw = getpwuid (uid);
if (pw)
{
puts (pw->pw_name);
exit (EXIT_SUCCESS);
}
fprintf (stderr,"%s: cannot find username for UID %u\n",
_PROGRAM_NAME, (unsigned) uid);
exit (EXIT_FAILURE);
}
Just take main lines and encapsulate it in class:
class Env{
public:
static std::string getUserName()
{
uid_t uid = geteuid ();
struct passwd *pw = getpwuid (uid);
if (pw)
{
return std::string(pw->pw_name);
}
return {};
}
};
For C only:
const char *getUserName()
{
uid_t uid = geteuid();
struct passwd *pw = getpwuid(uid);
if (pw)
{
return pw->pw_name;
}
return "";
}
#include <iostream>
#include <unistd.h>
int main()
{
std::string Username = getlogin();
std::cout << Username << std::endl;
return 0 ;
}
Another way is this -
#include <iostream>
using namespace std;
int main()
{
cout << system("whoami");
}
Use char *cuserid(char *s) found in stdio.h.
#include <stdio.h>
#define MAX_USERID_LENGTH 32
int main()
{
char username[MAX_USERID_LENGTH];
cuserid(username);
printf("%s\n", username);
return 0;
}
See for more details:
https://pubs.opengroup.org/onlinepubs/007908799/xsh/cuserid.html
https://serverfault.com/questions/294121/what-is-the-maximum-username-length-on-current-gnu-linux-systems
working a little bit through modern c++ specs
static auto whoAmI = [](){ struct passwd *tmp = getpwuid (geteuid ());
return tmp ? tmp->pw_name : "onlyGodKnows";
}
Today I had to do the same thing, but didn't like to include any OS specific headers. So here is what you can do in a cross-platform way without resorting to any Linux/Windows specific headers:
#include <stdio.h>
#include <memory>
#include <stdexcept>
#include <array>
#include <regex>
std::string execute_command(std::string cmd)
{
std::array<char, 128> buffer;
std::string result;
#if defined(_WIN32)
#define POPEN _popen
#define PCLOSE _pclose
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define POPEN popen
#define PCLOSE pclose
#endif
std::unique_ptr<FILE, decltype(&PCLOSE)> pipe(POPEN(cmd.c_str(), "r"), PCLOSE);
if (!pipe)
{
throw std::runtime_error("popen() failed!");
}
while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr)
{
result += buffer.data();
}
return result;
}
std::string get_current_username()
{
#if defined(_WIN32)
// whoami works on windows as well but it returns the name
// in the format of `computer_name\user_name` so instead
// we use %USERNAME% which gives us the exact username.
#define USERNAME_QUERY "echo %USERNAME%"
#elif defined(unix) || defined(__unix__) || defined(__unix)
#define USERNAME_QUERY "whoami"
#endif
auto username = execute_command(USERNAME_QUERY);
// this line removes the white spaces (such as newline, etc)
// from the username.
username = std::regex_replace(username, std::regex("\\s"), "");
return username;
}
This works just fine on both Linux and Windows and is C++11 compatible!
Test it online: https://paiza.io/projects/e/xmBuf3rD7MhYca02v5V2dw?theme=twilight
OKay, so I'm trying to set some global variables that can be accessed by the rest of my program by including a header file. However, XCode is telling me that I have duplicate symbols. Can anyone help?
Error: Duplicate symbol _ArrowKey in /Path/to/MKDBControlInterface.o /Path/to/main.o
main.h: // The global variables to be accessed...
#ifndef _main_h
#define _main_h
#include <map>
std::map<int,bool> ArrowKey;
#endif
MKDBControlInterface.h:
#ifndef _MKDBControlInterface_h
#define _MKDBControlInterface_h
#include <map>
#include <GLUT/glut.h>
#include "main.h"
#include "MKDBApplication.h"
class MKDBControlInterface {
public:
MKDBControlInterface( MKDBApplication& App )
: m_App( App )
{
glutSpecialFunc( SpecialListener );
glutSpecialUpFunc( SpecialListenerX );
ArrowKey[GLUT_KEY_LEFT] = false;
ArrowKey[GLUT_KEY_RIGHT] = false;
ArrowKey[GLUT_KEY_UP] = false;
ArrowKey[GLUT_KEY_DOWN] = false;
}
~MKDBControlInterface(){}
void static SpecialListener( int key, int x, int y ){
ArrowKey[key] = true;
}
void static SpecialListenerX( int key, int x, int y ){
ArrowKey[key] = false;
}
private:
MKDBApplication& m_App;
};
#endif
main.cpp
#include "main.h"
#include "MKDBApplication.h"
#include "MKDBControlInterface.h"
#include "MKDBRender.h"
int main( int argc, char *argv[] ){
MKDBApplication App;
MKDBControlInterface Interface( App );
MKDBRender Render( App );
return 0;
}
In main.h you need to declare ArrowKey as
extern "C" std::map<int,bool> ArrowKey;
and in main.cpp after the includes you should define it:
std::map<int,bool> ArrowKey;
BTW, I would also replace #ifndef/#define/#endif with #pragma once in the headers.
I am now writing wrappers for C++ functions, such that they can be used from C code.
The idea is to compile the cpp files using g++ and the c files using gcc, then link them together (!), but exposing ONLY those functions that are needed, to the C programs, by making them available in a header file 'test.h' (or maybe test.hpp?), like so:
(Note how I do not expose function 'vector Tokenize(const string& str,const string& delimiters)')
test.h:
/* Header can be read by both C+ and C compilers, just the way we want! */
#ifndef TEST_H
#define TEST_H
#ifdef __cplusplus
extern "C" {
#endif
#if defined(__STDC__) || defined(__cplusplus)
extern int TokenizeC(const char* text, const char* delim, char ***output); /* ANSI C prototypes */
extern void reclaim2D(char ***store, unsigned int itemCount);
#endif
#ifdef __cplusplus
}
#endif
#endif /* TEST_H */
test.cpp:
#include <string>
#include <iostream>
#include <vector>
#include <assert.h>
#include "test.h"
using namespace std;
vector<string> Tokenize(const string& str,const string& delimiters)
{
vector<string> tokens;
string::size_type delimPos = 0, tokenPos = 0, pos = 0;
if(str.length() < 1) return tokens;
while(1)
{
delimPos = str.find_first_of(delimiters, pos);
tokenPos = str.find_first_not_of(delimiters, pos);
if(string::npos != delimPos)
{
if(string::npos != tokenPos)
{
if(tokenPos < delimPos) tokens.push_back(str.substr(pos,delimPos-pos));
else tokens.push_back("");
}
else tokens.push_back("");
pos = delimPos + 1;
}
else
{
if(string::npos != tokenPos) tokens.push_back(str.substr(pos));
else tokens.push_back("");
break;
}
}
return tokens;
}
int TokenizeC(const char* text, const char* delim, char ***output)
{
if((*output) != NULL) return -1; /* I will allocate my own storage, and no one tells me how much. Free using reclaim2D */
vector<string> s = Tokenize(text, delim);
// There will always be a trailing element, that will be blank as we keep a trailing delimiter (correcting this issue would not be worth the time, so this is a quick workaround)
assert(s.back().length() == 0); // This will be nop'ed in release build
s.pop_back();
(*output) = (char **)malloc(s.size() * sizeof(char *));
for(vector <string>::size_type x = 0; x < s.size(); x++)
{
(*output)[x] = strdup(s[x].c_str());
if(NULL == (*output)[x])
{
// Woops! Undo all
// TODO : HOW to test this scenario?
for(--x; x >= 0; --x)
{
free((*output)[x]);
(*output)[x] = NULL;
}
return -2;
}
}
return x; /* Return the number of tokens if sucessful */
}
void reclaim2D(char ***store, unsigned int itemCount)
{
for (int x = 0; itemCount < itemCount; ++x)
{
free((*store)[x]);
(*store)[x] = NULL;
}
free((*store));
(*store) = NULL;
}
poc.c:
#include <stdio.h>
#include "test.h"
int main()
{
const char *text = "-2--4--6-7-8-9-10-11-", *delim = "-";
char **output = NULL;
int c = TokenizeC(text, delim, &output);
printf("[*]%d\n", c);
for (int x = 0; x < c; ++x)
{
printf("[*]%s\n", output[x]);
}
reclaim2D(&output, c);
return 0;
}
Do you notice something wrong?
For starters, when I ran this program, I got "Unsatisfied code symbol '__gxx_personality_v0'"
Thankfully, there is something here : What is __gxx_personality_v0 for?
Once I ran g++ with options " -fno-exceptions -fno-rtti", the output now fails with "Unsatisfied data symbol '_ZNSs4_Rep20_S_empty_rep_storageE'"
Ofcourse, the two environments (the one to compile - HP-UX B.11.23 ia64 and the one to run the binary on - HP-UX B.11.31 ia64) have different library versions (but same architecture), and this should not be a reason for the errors.
I would also like to test out the case marked by "// TODO : HOW to test this scenario?", but that can wait for now.
Any pointers?
The easiest way to avoid undefined symbols while linking is to link with g++ (not gcc). You can still compile your .c file with gcc, though.
Also please use system at a time. The link error may go away if you run all your gcc and g++ commands on the same system (no matter the old or the new one).
To call a C++ function from C, you can't have mangled names. Remove the conditional test for __cplusplus where you do the extern "C". Even though your functions will be compiled by a C++ compiler, using extern "C" will cause it to avoid name-mangling.
Here is an example:
The C file.
/* a.c */
#include "test.h"
void call_cpp(void)
{
cpp_func();
}
int main(void)
{
call_cpp();
return 0;
}
The header file.
/* test.h */
#ifndef TEST_H
#define TEST_H
extern "C" void cpp_func(void);
#endif
The CPP file.
// test.cpp
#include <iostream>
#include "test.h"
extern "C" void cpp_func(void)
{
std::cout << "cpp_func" << std::endl;
}
The compiler command line.
g++ a.c test.cpp
Is there a reason why you haven't considered modifying Swig to do just this? I seem to remember that there is a developmental branch of Swig to do just this...