Not familiar with c++, can someone help me add cmd to the myStr array and pass it to the main() function, here is what I have so far:
JNIEXPORT void JNICALL Java_my_package_JNIActivity_callCmdLine(
JNIEnv *env, jobject obj, jstring cmd)
{
const char *nativeString = env->GetStringUTFChars(cmd, 0);
env->ReleaseStringUTFChars(cmd, nativeString);
char * myStr [] = {"v", nativeString};
//int main(int argc, char *argv[])
main(1, myStr);
}
Well, don't release it before you're finished with it.
char * nativeString;
{ const char * _nativeString = env->GetStringUTFChars(cmd, 0);
nativeString = strdup (_nativeString);
env->ReleaseStringUTFChars(cmd, _nativeString);
}
char * myStr [] = {"v", nativeString};
main(1, myStr);
free (nativeString);
Why not taking advantage of objects to garantee deletion is done automatically...?
class ConvertStringHelper
{
public:
ConvertStringHelper( JNIEnv *env, jstring value )
{
m_str = env->GetStringUTFChars(value, 0);
m_value = &value;
m_env = env;
}
~ConvertStringHelper()
{
m_env->ReleaseStringUTFChars( *m_value, m_str);
}
jstring* m_value;
const char *m_str;
JNIEnv *m_env;
};
Then:
ConvertStringHelper helper( env, cmd );
const char* nativeStr = helper.m_str;
// nativeStr is valid in helper's scope and memory will be cleanly released when exiting the scope!
Related
I use macros to allocate memory via JNI and then write to that memory.
#MacroAllocator
case class SomeCaseClass(a: Int, b: Int, c: Int)
3 * INT.BYTES = 12, so it means I need to allocate 12 bytes of memory.
I wrote a buffer that stores offheap objects. and if i already get address of buffer i can reuse that address to write/read.
typedef struct {
uint8_t *buf;
size_t size;
} buf_t;
via jni i'm allocating memory (assume it's at compile time)
JNIEXPORT jlong JNICALL Java_some_package_com_1alloc(JNIEnv *env, jobject self, jint size) {
globalenv = env;
buf_t buf;
buf_alloc(&buf, (size_t) size);
jlong buf_addr = (jlong)buf.buf;
return buf_addr;
}
and then i'm trying to write something to that buf, it's okay too (compile time too)
JNIEXPORT void JNICALL Java_some_package_com_1write_1int(JNIEnv *env, jobject self, jint value, jint idx, jlong buf_addr) {
globalenv = env;
uint8_t *buf = (uint8_t*) buf_addr;
write_int_to_buf_at(buf, idx, value);
return;
}
and when everything is done, i'm trying to read (runtime):
JNIEXPORT jint JNICALL Java_some_package_com_read_1int(JNIEnv *env, jobject self, jint idx, jlong buf_addr) {
globalenv = env;
uint8_t *buf = (uint8_t*)buf_addr;
int32_t value = read_int_in_buf_at(buf, (size_t) idx);
return value;
}
UPD: read_int_in_buf_at func impl
int32_t read_int_in_buf_at(uint8_t *buf, size_t idx) {
uint8_t b3 = buf[idx + 3];
uint8_t b2 = buf[idx + 2];
uint8_t b1 = buf[idx + 1];
uint8_t b0 = buf[idx];
return (b3 << 24) | ((b2 & 255) << 16) |
((b1 & 255) << 8) | (b0 & 255);
}
i get some weird results when trying to read: 0, 1234125360, -1342346458, etc.
Continuing from the comments, you have to keep in mind that Java_some_package_com_1alloc returns the address of allocated memory (buf.buf) NOT the buf_t struct itself.
This means your functions have to change accordingly:
JNIEXPORT void JNICALL Java_some_package_com_1write_1int(JNIEnv *env, jobject self, jint value, jint idx, jlong buf_addr) {
globalenv = env;
// The `jlong` value is the address of allocated memory
uint8_t *buf = (uint8_t*) buf_addr;
write_int_to_buf_at(buf, idx, value);
}
and the reader:
JNIEXPORT jint JNICALL Java_some_package_com_read_1int(JNIEnv *env, jobject self, jint idx, jlong buf_addr) {
globalenv = env;
uint8_t *buf = (uint8_t*) buf_addr;
int32_t value = read_int_in_buf_at(buf, (size_t) idx);
return value;
}
I am rather new to handle C callbacks in C++. I made a sqlite wrapper c++ class, which just calls sqlite3_exec().
static int callback(void *NotUsed, int argc, char **argv, char **azColName){
SqliteAccessor* sqlite = static_cast<SqliteAccessor*> NotUsed;
if(argc > 0) {
sqlite->set_table_exists(true);
}
return 0;
}
class SqliteAccessor{
public:
bool has_table(const string dbName, const string tblName)
{
string sql;
sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
int rc = sqlite3_exec(m_db, sql.c_str(), callback, (void*) this, &zErrMsg);
if( rc != SQLITE_OK ){
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
// anyway to return the result directly?
// return hasTable;
}
// can I avoid the following methods and the member variable?
void set_table_exists(bool isExist) { m_table_exist = isExist; }
bool get_table_exists() { return m_table_exist; }
private:
static bool m_table_exist;
};
int caller(){
SqliteAccessor sqlite;
// to check if table exist
if (sqlite->has_table()){
// will above work or
// I should do with an extra call to query the changed state?
}
}
Now, I am quite confused how the caller can get the result from sqlite wrapper. I think, the caller cannot have the result by simply calling has_table(), because the result is returned from the callback, by set_table_exists(). So shall the caller get the result by making another call, e.g. call sqlite->get_table_exists() ?
Then this implies for every callback, I need to make a member variable (also has to be static) in class SqliteAccessor, and a pair of set/get_state(), which will be very cumbersome.
How to design the class to make it nice to use by caller?
Unfortunately, our code base does not support c++11.
If you are on C++11 consider using a lambda instead of a callback.
class SqliteAccessor{
public:
bool has_table(const string dbName, const string tblName)
{
bool hasTable = false;
string sql;
sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
int rc = sqlite3_exec(m_db, sql.c_str(), [&](void *NotUsed, int argc, char **argv, char **azColName){
SqliteAccessor* sqlite = static_cast<SqliteAccessor*> NotUsed;
if(argc > 0) {
hasTable = true;
}
}
, (void*) this, &zErrMsg);
if( rc != SQLITE_OK ){
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
return hasTable;
}
};
If you don't have access to C++11, you can always manually write your functor. You lose a bit of conciseness and locality though. The nice part is that the functor can save the state you need.
struct callback{
bool operator(void *NotUsed, int argc, char **argv, char **azColName)
{
SqliteAccessor* sqlite = static_cast<SqliteAccessor*> NotUsed;
if(argc > 0) {
hasTable = true;
}
return false;
}
bool hasTable;
};
class SqliteAccessor{
public:
bool has_table(const string dbName, const string tblName)
{
bool hasTable = false;
string sql;
sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
callback c;
int rc = sqlite3_exec(m_db, sql.c_str(), c, (void*) this, &zErrMsg);
if( rc != SQLITE_OK ){
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
return c.hasTable;
}
};
The way I would do it is to make the callback a private static member function and basically do what you did. Like this:
class SqliteAccessor
{
public:
bool has_table(const std::string dbName, const std::string tblName);
private:
static int callback(void *NotUsed, int argc, char **argv, char **azColName);
bool m_hasTable;
};
int SqliteAccessor::callback(void *NotUsed, int argc, char **argv, char **azColName)
{
SqliteAccessor* sqlite = static_cast<SqliteAccessor*>(NotUsed);
if(argc > 0) sqlite->m_hasTable = true;
return 0;
}
bool SqliteAccessor::has_table(const std::string dbName, const std::string tblName)
{
m_hasTable = false;
string sql = "SELECT " + quote_string(tblName) + "FROM " + quote_string(dbName)
+ "WHERE type = 'table' AND name = " + quote_string(tblName) + ";";
char *zErrMsg = 0;
int rc = sqlite3_exec(m_db, sql.c_str(), callback, (void*) this, &zErrMsg);
if( rc != SQLITE_OK )
{
printf("SQL error: %s", zErrMsg);
sqlite3_free(zErrMsg);
}
return m_hasTable;
}
int caller()
{
SqliteAccessor sqlite;
// to check if table exist
if (sqlite.has_table())
{
// do stuff :)
}
}
If sqlite3_exec() does not work with static functions, you can try with a global function like this:
class SqliteAccessor
{
public:
bool has_table(const std::string dbName, const std::string tblName);
private:
bool m_hasTable;
friend int callback(void *NotUsed, int argc, char **argv, char **azColName);
};
int callback(void *NotUsed, int argc, char **argv, char **azColName)
{
SqliteAccessor* sqlite = static_cast<SqliteAccessor*>(NotUsed);
if(argc > 0) sqlite->m_hasTable = true;
return 0;
}
I have just started using visualgdb
#include <string.h>
#include <jni.h>
#include <stdio.h>
int s_ButtonPressCounter = 0;
jstring
Java_com_visualgdb_example_AndroidProject1_AndroidProject1_stringFromJNI( JNIEnv* env,
jobject thiz )
{
char szBuf[512];
sprintf(szBuf, "You have pressed this huge button %d times", s_ButtonPressCounter++);
jstring str = (*env)->NewStringUTF(env, szBuf);
return str;
}
I have my intelissense show error log
Expression must have pointer type.
I tried to change it to env.NewStringUTF(szBuf) but the build comes to error.
Maybe, you should replace
jstring str = (*env)->NewStringUTF(env, szBuf);
with
jstring str = env->NewStringUTF(env, szBuf);
or with
jstring str = (*env).NewStringUTF(env, szBuf);
the best way to keep a pointer in main changes reflected inside the class?
static unsigned char tmp[][20] = {"hello world", "bye world"};
class X {
unsigned char ** buffer;
public:
X(unsigned char* buff)
{
buffer = &buff;
}
void printThis()
{
DBG_MSG_FORMATED(".......> %s", *buffer);
}
};
int main (int argc, char * const argv[]) {
unsigned char * buff = new unsigned char[20];
memcpy(buff, tmp[0], 12);
X x(buff);
x.printThis();
memcpy(buff, tmp[1], 12);
x.printThis();
delete [] buff;
return EXIT_SUCCESS;
}
this works, but when I do the follow
buff = tmp[0];
x.printThis();
the printout doesnt print hello world again??? how to fix that
You'll need to use a pointer to pointer in your class (gulp!):
class X {
unsigned char ** buffer;
public:
X(unsigned char** buff)
{
buffer = buff;
}
void printThis()
{
DBG_MSG_FORMATED(".......> %s", *buffer);
}
};
And then pass in the address of the pointer during construction:
X x(&buff);
int main (int argc, char * const argv[]) {
unsigned char * buff = new unsigned char[20];
memcpy(buff, tmp[0], 12);
X x(buff);
x.printThis();
delete [] buff;
buff = tmp[1];
x.printThis();
return EXIT_SUCCESS;
}
After you have done delete buff;, your pointer buffer in the class is pointing at memory that has been deleted, which is very bad news.
If you want to store the actual address of buff, you would need to pass the address of buff and store that, like this:
char **buffer;
X(unsigned char** buff)
{
buffer = buff;
}
void printThis()
{
DBG_MSG_FORMATED(".......> %s", *buffer);
}
...
X x(&buff);
Or you could make buffer a reference to buff:
char*& buffer;
X(unsigned char*& buff) : buffer(buff) {}
(No other changes needed in class or other code - but note that you can't do buffer = some_other_buffer; at a later stage - that will change the value of buff to some_other_buffer, which is probably not what you expected).
You can do something thing as bellow (using a pointer to a pointer), but sincerally, this more a problem than a solution because you are unable to delete tmp without a good care with the pointer in class X
#include <cstdio>
#include <cstring>
static unsigned char tmp[][20] = {"hello world", "bye world"};
class X {
unsigned char ** buffer;
public:
X(unsigned char** buff)
{
buffer = buff;
}
void printThis()
{
printf(".......> %s", *buffer);
}
};
int main (int argc, char * const argv[]) {
unsigned char * buff = new unsigned char[20];
memcpy(buff, tmp[0], 12);
X x(&buff);
x.printThis();
buff = NULL;
buff = tmp[1];
x.printThis();
}
I just found an elusive bug in a program and it turned out to be because with optimization enabled, in something like the following sometimes the std::string is destroyed before processDocument() got the text out of it:
#include <stdio.h>
#include <spawn.h>
#include <string>
static void processDocument(const char* text) {
const char* const argv[] = {
"echo",
text,
NULL,
};
pid_t p;
posix_spawnp(&p, "echo", NULL, NULL, (char**) argv, environ);
}
static int mark = 'A';
static void createDocument() {
const char* vc;
std::string v = "ABCKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKKK42";
++mark;
v[0] = mark;
vc = v.c_str();
processDocument(vc);
}
int main() {
createDocument();
createDocument();
return(0);
}
How do I safely convert a std::string to a char* for use in execvp, posix_spawnp etc ?
I found out why it really was (here the actual minimal testcase):
std::string resultString;
const char* nodeText;
const char* altText;
resultString = "......whatever1.";
nodeText = resultString.c_str();
resultString = ".....whatever2..";
altText = resultString.c_str();
printf("%s\n", nodeText); // garbage
Bad idea.