C++ in Ruby C extensions, pointer problems - c++

I'm tryign to build a Ruby C extension that uses some c++ libraries. Problem is I can't even get a simple "hello world" to work.
//hello_world.cpp
#include <ruby.h>
static VALUE tosCore;
static VALUE my_function( VALUE self )
{
VALUE str = rb_str_new2( "Hello World!" );
return str;
}
extern "C"
void Init_hello_world( void )
{
tosCore = rb_define_module("Core");
rb_define_module_function(tosCore, "my_method", my_function, 0);
}
The output I get is
compiling hello_world.cpp
hello_world.cpp: In function 'void Init_hello_world()':
hello_world.cpp:17:67: error: invalid conversion from 'VALUE (*)(VALUE) {aka lon
g unsigned int (*)(long unsigned int)}' to 'VALUE (*)(...) {aka long unsigned in
t (*)(...)}' [-fpermissive]
In file included from c:/Ruby200/include/ruby-2.0.0/ruby.h:33:0,
from hello_world.cpp:2:
c:/Ruby200/include/ruby-2.0.0/ruby/ruby.h:1291:6: error: initializing argument
3 of 'void rb_define_module_function(VALUE, const char*, VALUE (*)(...), int)'
[-fpermissive]
make: *** [hello_world.o] Error 1
I'm no C/C++ expert. Ruby is my language. I have compiled a few thousand lines of C++ under Rice with no problem, but since I want this particular extension to compile under Windows, Rice is not an option.

It's because the function callback you present to rb_define_module_function is not what the compiler expects. It want a function looking like this:
VALUE my_function(...)
But your function is
VALUE my_function( VALUE self )
Notice the difference in the argument list.
One way to get rid of the error, is to type cast the argument to the type that rb_define_module_function expects:
rb_define_module_function(tosCore, "my_method",
reinterpret_cast<VALUE(*)(...)>(my_function), 0);
You can read about reinterpret_cast here.

Related

Two different results passing pointer-to-array to a function in C and C++?

I have a question regarding to the code snippet appended below. Anyway I ran the snippet on ideone.com and got two different results
C: Succeed.
C++: Error:
prog.cpp: In function ‘int main()’:
prog.cpp:20:13: error: cannot convert ‘int* (*)[2][10]’ to \
‘int* (*)[10]’ for argument ‘1’ to ‘void foo(int* (*)[10], size_t)’
foo(&a, LEN);
^
The result in C++ is what I expect, but it runs successfully in C, and it seems like it's compiler dependent because people on the chat helping ran the snippet only got a warning.
So which part I've missed? Is that C automatically did some conversion?
#include <stdio.h>
#include <stddef.h>
#define LEN 2
void foo(int* a[][10], size_t len) {
printf("%s\n", "successfully called foo.");
}
int main(void) {
// a is an LEN-array of an 10-array of (int *)
int *a[LEN][10] = {{0}};
// but the identifier `a` will decay to be a pointer of type int*[10]
// p1 is a pointer to an 10-array of (int *)
int *(*p1)[10] = 0;
foo(a, LEN);
foo(&a, LEN);
return 0;
}
Drastic edit; previous answer was wrong as pointed out in the comments.
The program is ill-formed in both C and C++. But the standards of the respective languages don't disallow successfully compiling programs that violate the imposed constraints. This allows the implementations to extend the language. Implementations are merely required to issue a diagnostic message. Both a warning and an error are conforming behaviours.
For whatever reason, the compiler that you use (through ideone) has chosen to behave differently when compiling C++.
This is not valid in C. Using gcc with -Wall -Wextra, it outputs the following:
x1.c: In function ‘main’:
x1.c:19:9: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
foo(&a, LEN);
^
x1.c:5:6: note: expected ‘int * (*)[10]’ but argument is of type ‘int * (*)[2][10]’
void foo(int* a[][10], size_t len) {
^~~
The types are not compatible. It only shows up as a warning because C tends to allow various pointer conversions even though they aren't proper.
You can however do this:
int *(*p1)[10] = a;
foo(a, LEN);
foo(p1, LEN);

error: cannot convert 'std::basic_string<char>::iterator ...' to 'const char* for argument '1' ...'

I'm getting the following error:
error: cannot convert 'std::basic_string<char>::iterator {aka __gnu_cxx::__normal
_iterator<char*, std::basic_string<char> >}' to 'const char*' for argument '1'
to 'int remove(const char*)'
For some reason, my program compiles perfectly when I'm working on a Mac... but once I use a Linux machine, this error pops up in more than one place.
Here's one of the instances where the error pops up:
SomeClass::SomeClass(string t, string art, Time dur) {
char chars[] = ",";
t.erase(std::remove(t.begin(), t.end(), chars[0]), t.end());
art.erase(std::remove(art.begin(), art.end(), chars[0]), art.end());
// Some more code ...
}
More specifically, the error is coming from this line:
t.erase(std::remove(t.begin(), t.end(), chars[0]), t.end());
Does anyone know how to approach this problem?
You forgot to #include <algorithm>, where std::remove is located. Without that, your compiler only knows about this std::remove (I get the same error with Visual C++ 14), which is defined in indirectly included <cstdio> header.
Different behavior among compilers is a result of different #include hierarchies of the standard library implementations.

C++ error C2664 with CStrings

I have some old C++ file which I know used to compile. I have created a new install of Visual C++ version 6.
I am getting lots of compile errors with CStrings about not being able to convert to const char *
Here's an example.
CString dogs = "test";
writeoutfile(dogs, 1);
void Crender::writeoutfile(CString data, long data_size) {}
I get this error:
error C2664: 'void __thiscall Crender::writeoutfile(const char *,long)' : cannot convert parameter 1 from 'class CString' to 'const char *'
Is there some way I can get round this?
You have to get the raw pointer to the char field. This can be done with
CString::GetBuffer()
so you could call
writeoutfile(dogs.GetBuffer(), 1);
CString should convert to const char*. Is it a Unicode build? That's the only explanation I can think of.
GetBuffer() is for getting a writeable pointer to the data contained inside CString. Don't do that!

Why does GCC accept convertion from 'const char *' to 'char *' on std::strrchr() returned value?

While adding a detailed answer, I noticed that GCC does not warn the following code while Visual C++ complains.
#include <cstring>
int main()
{
const char CONSTSTR[] = "foo/bar/foobar.txt";
char *nonconst = std::strrchr (CONSTSTR, '/');
// cannot convert from 'const char *' to 'char *'
*nonconst++ = 'B';
*nonconst++ = 'A';
*nonconst++ = 'D';
}
I have tested three different GCC versions:
4.1.2 on Red Hat (Linux)
4.5.3 on Cygwin (Windows)
4.7.2 on MinGW (Windows)
But all these three GCC versions compiled this code without any warning/error:
> g++ -Wall -Wextra -pedantic -ansi test.cpp && echo "success"
success
While Microsoft compiler v16 complains:
> cl -c test.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 16.00.30319.01 for 80x86
Copyright (C) Microsoft Corporation. All rights reserved.
test.cpp
test.cpp(5) : error C2440: 'initializing' : cannot convert from 'const char *' to 'char *'
Conversion loses qualifiers
(from my office, I do not have access to ideone/codepad/... to test it using other versions)
As this code uses std::strrchr, I do not understand why GCC does not complain.
const char* strrchr( const char* str, int ch ); //the code above uses this declaration
char* strrchr( char* str, int ch );
My question: Why does g++ successfully compile this code without any warning/error? Is it a bug? a feature? a miss-configuration on my side?
Actually your g++ does not accept the conversion from 'const char *' to 'char *', it's just that on your version std::strrchr() returns a char* (incorrectly, instead of a const char*).
To verify the first part of my statement, try to compile the following on your GCC versions, I predict that all will correctly issue an error:
int main()
{
const char* p = "foo";
char* q = p; // error, invalid conversion from 'const char*' to 'char*'
}
Now for the second part, I tried to compile the following minimal code, whose actual aim is to trigger an error in order to list the declared overloads of std::strrchr:
#include <cstring>
void (*p)() = &std::strrchr; // error here, with "candidates are: ..."
int main() {}
Well, with gcc 4.7.2 the message shows the expected "all non-const" and "all const" overloads:
prog.cpp:2:21: error: no matches converting function ‘strrchr’ to type ‘void (*)()’
In file included from /usr/include/c++/4.7/cstring:44:0,
from prog.cpp:1:
/usr/include/string.h:249:1: error: candidates are: char* strrchr(char*, int)
/usr/include/string.h:255:1: error: const char* strrchr(const char*, int)
i.e. the prototypes
char* strrchr( char* , int );
const char* strrchr( const char* , int ); // Question's code will use this one (-> error)
But with gcc 4.3.2 the message was different:
prog.cpp:2: error: no matches converting function 'strrchr' to type 'void (*)()'
/usr/include/string.h:171: error: candidates are: char* strrchr(const char*, int)
/usr/include/c++/4.3/cstring:118: error: char* std::strrchr(char*, int)
i.e. the overloads were
char* strrchr( const char* , int ); // Question's code would use this one (-> no error...)
char* strrchr( char* , int );
(the second one is the C++ non-const overload; but the first one is the old C version, and should instead be the C++ const overload).
This it seems that the headers (<cstring> and/or <string.h>) were incorrect on this version, and I suspect that it's the same on yours.
Edit: I found for example a discussion, a blog post and a bug report (for strchr not strrchr but it's the same story).

POSIX Thread Addition on XCode

The program should get arguments from a command line, and add the arguments via posix threads. But Xcode successfully builds it, but gives no output. Is there something wrong with this code.
Thanks
#include <iostream>
#include <pthread.h>
using namespace std;
void *Add(void *threadid){
long tid;
tid =(long)threadid;
long sum=0;
sum=sum+tid;
printf("%ld.\n",sum);
pthread_exit(NULL);
}
void *Print(void *threadid){
long tid;
tid =(long)threadid;
printf("%ld.\n",tid);
pthread_exit(NULL);
}
int main (int argc, char const *argv[])
{
if(argc<6){
printf("you need more arguments");
return -1;
}
long real[5];
pthread_t athread,bthread;
for (int x=1;x<=5;x++)
real[x-1]=atol(argv[x]);
for(int y=1;y<=5;y++)
pthread_create(athread[y],NULL,Add,(void *)&real[y]);
for(int y=1;y<=5;y++)
pthread_create(bthread[y],NULL,Print,(void *)&real[y]);
pthread_exit(NULL);
return 0;
}
First of all I think you should check if pthread_create method was success.
I don't have expirience in pthread under Apple, but based on that code I think you have problem with thread creation.
First of all, printf is defined in stdio.h and not in iostream. If you'd like to do it the C++ way with iostream, then cout << "Blabla " << var << endl; should be used instead.
Second, you are calling pthread_create with wrong arguments. As defined athread and bthread are not arrays but you use them as such. I am not entirely sure why this would even compile since pthread_create expects pthread_t* as first argument and you are providing *pthread_t. If the code ever compiles, it will most likely crash when run.
Third, you are not joining the adder threads. This means that your print threads could start before the adder threads have finished.
Fourth, you are summing into local variables. You are supposed to sum into a global one. Don't forget to guard the access to it by a mutex or something.
Fifth, arguments to the thread routines are wrong. You are passing pointer to the value and not the value itself and later reinterpreting the pointer as the value itself. You would most likely want to use (void *)real[y] and not (void *)&real[y]. Mind that casting long to void * doesn't work on all systems. On Mac OS X both long and void * are of the same length (either 32 or 64 bits) but this is not true in general.
Edited: Your code doesn't even compile on OS X:
$ g++ -o t.x t.cpp
t.cpp: In function ‘int main(int, const char**)’:
t.cpp:37: error: cannot convert ‘_opaque_pthread_t’ to ‘_opaque_pthread_t**’ for argument ‘1’ to ‘int pthread_create(_opaque_pthread_t**, const pthread_attr_t*, void* (*)(void*), void*)’
t.cpp:40: error: cannot convert ‘_opaque_pthread_t’ to ‘_opaque_pthread_t**’ for argument ‘1’ to ‘int pthread_create(_opaque_pthread_t**, const pthread_attr_t*, void* (*)(void*), void*)’
$ clang -o t.x t.cpp
t.cpp:37:5: error: no matching function for call to 'pthread_create'
pthread_create(athread[y],NULL,Add,(void *)&real[y]);
^~~~~~~~~~~~~~
/usr/include/pthread.h:304:11: note: candidate function not viable: no known
conversion from 'struct _opaque_pthread_t' to 'pthread_t *' (aka
'_opaque_pthread_t **') for 1st argument;
int pthread_create(pthread_t * __restrict,
^
t.cpp:40:5: error: no matching function for call to 'pthread_create'
pthread_create(bthread[y],NULL,Print,(void *)&real[y]);
^~~~~~~~~~~~~~
/usr/include/pthread.h:304:11: note: candidate function not viable: no known
conversion from 'struct _opaque_pthread_t' to 'pthread_t *' (aka
'_opaque_pthread_t **') for 1st argument;
int pthread_create(pthread_t * __restrict,
^
2 errors generated.
Don't you even see the error messages that XCode is providing?