I am writing a program that needs a pathname to eventually create a global string.
I currently have this pathname hard coded, but would like to use a global variable to replace this.
The problem I am having is that my global variable is undefined. I am also using JNI and the error I am getting is:
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00007f65f981ddd0, pid=11660, tid=140075985102592
#
# JRE version: 7.0_21-b02
# Java VM: OpenJDK 64-Bit Server VM (23.7-b01 mixed mode linux-amd64 compressed oops)
# Problematic frame:
# C [libstdc++.so.6+0x9ddd0] std::string::size() const+0x0
#
# Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again
#
# An error report file with more information is saved as:
# /home/cbil/Desktop/SIGH_Project/July_9/src/hs_err_pid11660.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
# https://bugs.launchpad.net/ubuntu/+source/openjdk-7/
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
and here is relevant code that is reformatted for simplicity:
file1.cpp
#include <jni.h>
#include "file1.h"
#include <iostream>
#include <fstream>
#include <string.h>
using namespace std;
const char* myPath;
JNIEXPORT jint JNICALL Java_foo_foo(JNIEnv *env, jobject thisobj, jbyteArray passedPath){
/*Some conversion, don't think it is relevant, but it might be*/
jboolean isCopy;
jbyte* path = env->GetByteArrayElements(passedPath,&isCopy);
int length1 = strlen((const char*)path);
char* convertedVar = (char*)malloc(length1+1);
memcpy(convertedVar,path,length1);
convertedVar[length1] = '\0';
convertedVar = (char*)path;
/*End Conversion*/
globalVariable = convertedVar;
... //Some code to use the variable and releases
}
file2.h (This is where I declare the global variable)
#include <vector>
#include <fstream>
#include <string.h>
extern const char* globalVariable;
extern int someNum;
extern int someLength;
class file2{
public:
static std::vector<std::string> getSomeString(int &someNum, int &someLength);
private:
static const std::vector<std::string> anotherVar;
...//some other variables and methods
}
and finally the code that calls getSomeString
file3.cpp
#include "file2.h"
#include <string.h>
#include <vector>
#include <fstream>
using namespace std;
int someNum = 0;
int someLength = 0;
const char* globalVariable;
vector<string> file2::getSomeString(int &someNum, iint &someLength){
vector<string> data;
ifstream infile(globalVariable); //I think the problem is here
string line;
...// some code that goes through the data file specified by the path name
someNum = data.size();
someLength = data[0].size();
return data;
}
const vector<string> file2::anotherVar = getSomeString(someNum,someLength); //variable that uses the getSomeString method
}
I'll say it here again, I am using JNI. I have gotten errors saying the lib.so file I create has undefined variables, I don't know if this is helpful information.
Any help would be appreciated. Sorry about the long post, I am quite lost.
char* convertedVar = (char*)malloc(length1+1);
memcpy(convertedVar,path,length1);
convertedVar[length1] = '\0';
convertedVar = (char*)path;
I'm pretty sure this last line shouldn't be there. You are going through this malloc/memcpy dance, then promptly drop this allocated-and-initialized block of memory on the floor, and make convertedVar point to something else instead.
Further, I'm pretty sure path pointer will become invalid as soon as the function returns.
extern const char* globalVariable;
This declares the variable, but doesn't define it. You also need to provide a definition, in exactly one source file (not in a header file):
const char* globalVariable;
Curiously, you know enough to do just that with someNum and someLength, but not for globalVariable.
Related
main.h: header
#ifndef _MAIN_H
#define _MAIN_H
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
typedef struct ComplexNum
{
double real;
double img;
}mc;
char *JustShow(mc );
#endif // _MAIN_H
cal.cpp : function defined in another file called
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "main.h"
char *JustShow(mc a)
{
char str1[100];
char str2[100];
char str3 [100];
sprintf(str1,"%f",a.real);
sprintf(str2,"%f",a.img);
strcat(str1," + ");
strcat(str1,str2);
strcat(str1,"i");
return(str1);
}
I tried to use the JustShow function in another file, but the compiler said undefined reference to 'JustShow'
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include "main.h"
int main()
{
mc y;
y.img = 4;
y.real = 3;
printf("%s",JustShow(y));
}
I am so confused why can't I use the function JustShow when I had already added "main.h". I am also confused why should we define the functions in the source file instead of the header.
I'm sorry if this is the basic knowledge I should learn about and not ask others.
I'm going to call the third piece of code "main.cpp".
why can't I use the function JustShow when I had already added "main.h".
Header files only inform a compiler that a function, variable or constant exist. You need to compile cal.cpp with main.cpp: g++ main.cpp cal.cpp -o main
I am also confused why should we define the functions in the source file instead of the header.
It makes code more organised.
It speeds up compile time.
You can read more about header files here
Some advice for your code:
Function JustShow is incorrect. Arrays are just pointers and you are returning a pointer to a local variable that are deleted after function returns. It means that it will be overwritten and you will lose data there (and trying to write there may crash your program). In order to make it work you can:
Give an array as an argument to the function. Then we would have void JustShow(mc a, char* str1);
create new array with new (or malloc if you wirte in C, not C++).
You don't need to concat so much. sprintf can do all of that:
void JustShow(mc a, char* str1) {
sprintf(str1,"%f + %fi", a.real, a.img);
}
I have a c++ (C++ 17) library and a function dependent on this library. I want to call this function from python(python 3). How can it be done?
I have read some tutorials using swig and ctypes but I don't know how can I make it work for an external shared library.
Details:
I have this libclickhouse-cpp-lib.so .so file and the header files for this library in /path/to/header/files directory.
/*File cpp_reader.h*/
#pragma once
int reader();
/* File cpp_reader.cpp*/
#include <clickhouse/client.h>
#include <iostream>
#include "cpp_reader.h"
using namespace clickhouse;
int reader()
{
Client client(ClientOptions().SetHost("localhost"));
int numrows=0;
client.Select("SELECT count(*) from test.test_table",
[&numrows] (const Block& block)
{
for (size_t i=0;i<block.GetRowCount();++i)
{
numrows+=block[0]->As<ColumnUInt64>()->At(i);
}
}
);
return(numrows);
}
I want to call this read function from python. I have gone through some posts using swig and ctypes but haven't been able to figure out. If it can be done easily using anything else, please suggest that too.
Additional Information:
This is how I run the code in c++
/*File: main.cpp*/
#include <clickhouse/client.h>
#include <iostream>
#include <Python.h>
using namespace clickhouse;
int main()
{
/// Initialize client connection.
Client client(ClientOptions().SetHost("localhost"));
int numrows=0;
client.Select("SELECT count(*) from test.test_table",
[&numrows] (const Block& block)
{
for (size_t i=0;i<block.GetRowCount();++i)
{
numrows+=block[0]->As<ColumnUInt64>()->At(i);
}
}
);
std::cout<<"Number of Rows: "<<numrows<<"\n";
}
Compilation:
g++ -std=c++1z main.cpp -I/path/to/header/files -I/usr/include/python3.6m/ -L. /path/to/libclickhouse-cpp-lib.so -o outfile
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/path/to/so_file/directory
export LD_LIBRARY_PATH
/path/to/so_file/directory contains libclickhouse-cpp-lib.so
./outfile
In your case it may be best to keep it simple and not use binding generators, because all you have here is a simple function that doesn't receive any parameters and simply returns an int.
Your goal can be achieved as follows:
In cpp_reader.cpp, prepend the following line before the reader definition:
extern "C" __attribute__ ((visibility ("default")))
int reader()
{
....
Now from Python you can simply do:
from ctypes import cdll
import os
lib = cdll.LoadLibrary(os.path.abspath("libclickhouse-cpp-lib.so"))
num_rows = lib.reader()
Also don't forget to add -shared to the g++ commandline when compiling the shared object
I am trying to unit test an HTTP API written in C++:
void getLogNames(Request & req, Response & res)
{
vector<string> files = getFilesInDirectory(LOG_LOCATION, ".log", false);
json response(files);
res.send(response);
}
The problem is that LOG_LOCATION is included from common.h and is const, and can't be changed by my testing code:
const std::string LOG_LOCATION = "/var/log"
I've tried doing this at the top of the file:
#ifdef UNIT_TEST
#include <common_mock.h>
#else
#include <common.h>
#endif
However, common.h is included in some shared libraries that are being linked in, and I would have to add UNIT_TEST hooks to all those files and rebuild the shared libraries as well, which I would rather avoid...
Is there an easier way I could be doing this, some #define tricks or something?
Well, you can try to const_cast a pointer to your LOG_LOCATION but it's dirty and unreliable solution and may cause seg fault. For example:
original_file.h
#include <iostream>
const std::string LOG_LOCATION = "/var/log";
int func() {
std::cout << LOG_LOCATION << std::endl;
}
unit_test.cpp
#include "test.h"
void someUnitTest() {
const std::string* cs = &LOG_LOCATION;
std::string* s = const_cast<std::string*>(cs);
*s = "NEW_VALUE";
std::cout << *s;
}
int main() {
someUnitTest();
}
This code may work in some cases (i.e. this successfully compiled and worked in GCC but only for class object type - it crashes with buildin type like int) but is may change with different compilers, platforms, or optimization levels.
The recommended way is to redesign your application and use dependency injections, for example wrap your function calls in a class and put this location as a settable member.
Why don’t you change your class to receive the log location in its constructor? By hardcoding it (macros are eqivalent to hardcoding from the testing point of view) you’re purposely making your class less testable.
I need to share some variables among different source files. Now I use namespace like below, which seems a little odd.
Adding const may be better, but the global variables will be
assigned by loading configure file together not one for one time. So the initializer_list can't be used. Is there any better solution for it?
// configuration.hpp
#include <string>
namespace configuration {
extern int ni;
extern int nk;
extern int nt;
extern double dt;
extern std::string grid_config_file;
extern std::string media_config_file;
extern std::string source_config_file;
void SetConfiguration(const std::string &);
};
// configuration.cc
#include "configuration.hpp"
#include <string>
#include <yaml-cpp/yaml.h>
namespace configuration {
int ni;
int nk;
int nt;
double dt;
std::string grid_config_file;
std::string media_config_file;
std::string source_config_file;
void SetConfiguration(const std::string &main_config) {
YAML::Node config = YAML::LoadFile(main_config);
YAML::Node conf_basic = config["conf_basic"];
ni = conf_basic["ni"].as<int>();
nk = conf_basic["nk"].as<int>();
nt = conf_basic["nt"].as<int>();
dt = conf_basic["dt"].as<double>();
YAML::Node conf_file = config["conf_file"];
grid_config_file = conf_file["grid_conf"].as<std::string>();
media_config_file = conf_file["media_conf"].as<std::string>();
source_config_file = conf_file["source_conf"].as<std::string>();
}
}
The configure file(conf.yaml)
---
# The basic parameters
conf_basic:
ni: 100
nk: 100
nt: 200
dt: 0.1
# The detailed configure files
conf_file:
grid_conf: Grid.yaml
media_conf: Media.yaml
source_conf: Source.yaml
Please take a look at Singleton design pattern. You can wrap the variables inside a public class and access them through a static method. At the first access you initialize the variables from whereever you need.
i am trying to make user threads in C++, so while trying to initialize them i am getting a compiler error :translate_address was not declared in this scope
#include <iostream>
#include <cstdlib>
#include <csignal>
#include <csetjmp>
#define JB_SP 6 //Location in the code
#define JB_PC 7 //Stack pointer
#define STACK_SIZE 10
typedef unsigned long address_t; //64bit address
sigjmp_buf jbuf[3];
char stack1[STACK_SIZE];
void f(){
}
void setup(){
unsigned int sp, pc;
sp = (address_t)stack1 + STACK_SIZE - sizeof(address_t);
pc = (address_t)f;
sigsetjmp(jbuf[0],1);
(jbuf[0]->__jmpbuf)[JB_SP] = translate_address(sp);
(jbuf[0]->__jmpbuf)[JB_PC] = translate_address(pc);
sigemptyset(&jbuf[0]->__saved_mask);//empty saved signal mask
}
int main(){
return 1;
}
am i meant to include it some how? or is there a different problem?
thank you.
translate_address is not a Linux function. If you're referring to some kind of book or example code, it should explain where you're supposed to get this function from. If it doesn't, chances are it's not meant for Linux (or is a really, really bad reference/example).
Furthermore, you should NOT modify the contents of jmp_buf or sigjmp_buf directly. These are architecture and platform-dependent structures, and only the C library is allowed to mess with them. Since the contents of the structures are OS-dependent, if you're using a reference intended for some other OS when modifying sigjmp_buf, Bad Things will happen.
You should instead either use setcontext, getcontext, and makecontext for user threads (fibers) or pthread_create for OS-level threads.