I have been stuck on this all afternoon, and even tried the following search: "c++ passing pointer to array via function", and can't find a working answer, so here is my question.
Before I begin, please, this is NOT an OpenGL question, this is an array pointer passing question.
Also, don't get '....' (4 dot) mixed up with '...' (3 dot). There is a lot of code I am skipping over with '....' (4 dot), the ... (3 dots) are the ellipse parameter for variable number of paramters passed to a function.
These are the snippets from the four files involed:
OpenGL.h
class OpenGL {
.... (other unrelated stuff)
public:
int * iPixelFormatAttribList[]; <----------
....
utilities.h
template <typename T> void LoadArray (T * [], int, ...); <--------
utilities.cpp
// Dynamically Load Array.
template <typename T>
void LoadArray (T * Dest [], int count, ...) { <-------
va_list list;
va_start(list,count);
T * temp [] = new T [count];
for (int cnt = 0; cnt < count; cnt++)
* Dest[cnt] = va_arg(list, T);
va_end(list);
Dest = temp;
delete [] temp;
}
OpenGL.cpp
void OpenGL::V3_SetupPixelFormat() {
.....
LoadArray (
iPixelFormatAttribList, 15, <---------
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0
// End of attributes list
);
Ok, So, here what I am trying to do. I know that in a class definition, (OpenGL.h, the OpenGL class), that space is not allocated for any members, and because when I create it, I do not know how many paramters I am going need for an array, I need to find a way to dynamically allocate and setup the list so I can pass it into later OpenGL calls.
(Another reason I decided to setup a dynamic loading list like this was because there are several arrays involved like this, loading arrays, and I may also need this same type of functionality later with doubles and what not for vector data. Creating this utility template seems a forward thinking way to go.)
This all LOOKS Ok, and in fact, it compiles clean, but it does not link. I get the following:
**** Internal Builder is used for build ****
windres --use-temp-file -i..\res\resource.rc -o..\res\resource_rc.o
g++ -D_SS_DEBUG_ -ID:\Dev\Projects\Eclipse\OpenGL3\res -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu++0x -o src\OpenGL.o ..\src\OpenGL.cpp
g++ -D_SS_DEBUG_ -ID:\Dev\Projects\Eclipse\OpenGL3\res -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu++0x -o src\main.o ..\src\main.cpp
g++ -D_SS_DEBUG_ -ID:\Dev\Projects\Eclipse\OpenGL3\res -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu++0x -o src\Utilities.o ..\src\Utilities.cpp
g++ -D_SS_DEBUG_ -ID:\Dev\Projects\Eclipse\OpenGL3\res -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu++0x -o src\App.o ..\src\App.cpp
g++ -D_SS_DEBUG_ -ID:\Dev\Projects\Eclipse\OpenGL3\res -O0 -g3 -Wall -c -fmessage-length=0 -std=gnu++0x -o src\Win.o ..\src\Win.cpp
g++ -o OpenGL3.exe src\main.o src\Win.o src\Utilities.o src\OpenGL.o src\App.o ..\res\resource_rc.o -lopengl32 -lglew32 -lglu32 -lkernel32 -lgdi32 -lcomdlg32 -luser32
src\OpenGL.o: In function `ZN6OpenGL19V3_SetupPixelFormatEv':
D:\Dev\Projects\Eclipse\OpenGL3\Debug/../src/OpenGL.cpp:54: undefined reference to `void LoadArray<int>(int**, int, ...)'
collect2: ld returned 1 exit status
Build error occurred, build is stopped
Time consumed: 3000 ms.
The key line to me looks like:
undefined reference to `void LoadArray<int>(int**, int, ...)'
What this seems to tell is the way I am calling the function:
LoadArray (
iPixelFormatAttribList, 15,
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
....
And the way I am defining the template function:
template <typename T> void LoadArray (T * [], int, ...);
and:
template <typename T>
void LoadArray (T * Dest [], int count, ...) {
don't match. I get that much.
What I don't get is how to adjust the template (Or the call) so that they match so it can link (i.e. I got my function signatures all screwed up.)
The basic idea to this is, I call LoadArray with an array pointer, the element count, and the list of elements, and it modifies the pointer so that it points to a new list containing the array elements.
I am sure there are fancy C++ ways to do this, but I want to understand how to make this work as it seems it should here. (i.e. it would help me to learn if I know what exactily I was doing wrong here, rather then a redirect solution that won't teach me what I did wrong, I know enough to know I am missing something in the syntax of passing an array pointer like this, I just can't figure out the right black magic to get it right.)
Thanks.
Move your all your template code to the header file. That makes straight forward for the compiler to instantiate instances of your template class for different template parameters. If you don't do this then you need to force instantiation of the template for the types you need.
Why don't you just define your template as
template <typename T>
void LoadArray(T **Dest, int count, ...) {
And be done with it?
Related
I would like to compile a shared library using both symbol versioning and link-time optimization (LTO). However, as soon as I turn on LTO, some of the exported symbols vanish. Here is a minimal example:
Start by defining two implementations of a function fun:
$ cat fun.c
#include <stdio.h>
int fun1(void);
int fun2(void);
__asm__(".symver fun1,fun#v1");
int fun1() {
printf("fun1 called\n");
return 1;
}
__asm__(".symver fun2,fun##v2");
int fun2() {
printf("fun2 called\n");
return 2;
}
Create a version script to ensure that only fun is exported:
$ cat versionscript
v1 {
global:
fun;
local:
*;
};
v2 {
global:
fun;
} v1;
First attempt, compile without LTO:
$ gcc -o fun.o -Wall -Wextra -O2 -fPIC -c fun.c
$ gcc -o libfun.so.1 -shared -fPIC -Wl,--version-script,versionscript fun.o
$ nm -D --with-symbol-versions libfun.so.1 | grep fun
00000000000006b0 T fun##v2
0000000000000690 T fun#v1
..exactly as it should be. But if I compile with LTO:
$ gcc -o fun.o -Wall -Wextra -flto -O2 -fPIC -c fun.c
$ gcc -o libfun.so.1 -flto -shared -fPIC -Wl,--version-script,versionscript fun.o
$ nm -D --with-symbol-versions libfun.so.1 | grep fun
..no symbols exported anymore.
What am I doing wrong?
WHOPR Driver Design gives some strong hints to what is going on. The function definitions fun1 and fun2 are not exported according to the version script. The LTO plugin is able to use this information, and since GCC does not peek into the asm directives, it knows nothing about the .symver directive, and therefore removes the function definition.
For now, adding __attribute__ ((externally_visible)) is the workaround for this. You also need to build with -flto-partition=none, so that the .symver directives do not land by accident in a different intermediate assembler file than the function definition (where it will not have the desired effect).
GCC PR 48200 tracks an enhancement request for symbol versioning at the compiler level, which would likely address this issue as well.
It looks like my externally_visible fix works. This is:
#define DLLEXPORT __attribute__((visibility("default"),externally_visible))
DLLEXPORT int fun1(void);
Also see: https://gcc.gnu.org/onlinedocs/gccint/WHOPR.html
But I think your versionscript is wrong.
If I take out the visibility overrides and change your versionscript by adding fun1 and fun2 then it works. Like:
v1 {
global:
fun; fun1;
local:
*;
};
v2 {
global:
fun; fun2;
} v1;
The symbol alias targets have to be visible as well as the alias.
I just hit the same problem - so thank you for asking this. However I've found it to be more clean to use __attribute__((used)). Since gcc is not scanning the top level assembler, it can't figure out that fun1 and fun2 are being used ... so it removes them. So it looks to me that changing definition to:
__asm__(".symver fun1,fun#v1");
int __attribute__((used)) fun1() {
printf("fun1 called\n");
return 1;
}
should be sufficient.
This question already has answers here:
Can I name a variable with the same name as a typedef'd structure name?
(5 answers)
Closed 5 years ago.
I'm building a hash table in C.
Everything seems to work fine except this variable, cur_item, that report me an error at compilation.
Here is the code :
void insert(hash_table* ht, const char* key, const char* value) {
const int load = ht->count * 100 / ht->size;
if (load > 70) {
resize_up(ht);
}
item* item = new_item(key, value);
int index = get_hash(item->key, ht->size, 0);
item* cur_item = ht->items[index];
int i = 1;
while (cur_item != NULL) {
/** PROCESS **/
}
}
Here is my Makefile (not the best one I guess):
main: main.o hash_table.o prime.o
gcc -g -Wall -lm -o main.out ./build/main.o ./build/hash_table.o ./\
build/prime.o
main.o: ./src/main.c ./src/hash_table.h
gcc -c ./src/main.c -o ./build/main.o
hash_table.o: ./src/hash_table.c ./src/hash_table.h
gcc -c ./src/hash_table.c -o ./build/hash_table.o
prime.o: ./src/prime.c ./src/prime.h
gcc -c ./src/prime.c -o ./build/prime.o
And here is the error :
./src/hash_table.c: In function ‘insert’:
./src/hash_table.c:65:9: error: ‘cur_item’ undeclared (first use in this function); did you mean ‘del_item’?
item* cur_item = ht->items[index];
^~~~~~~~
del_item
./src/hash_table.c:65:9: note: each undeclared identifier is reported only once for each function it appears in
make: *** [Makefile:10: hash_table.o] Error 1
The type item represent a structure I created.
del_item is a function, no reason to use it there.
If I declare cur_item before the if loop and then initialize its value after the get_hash() function, the compilation works fine.
Can someone explain me why the first compilation failed ? Is there something missing in my Makefile ?
You just overloaded the identifier item to be a variable. So then the compiler is confused and does not know what you want when you try to declare cur_item.
Don't use the same name for a variable and a type. Obviously this confuses you and the compiler.
I'm trying to implement a simple integration of R with C. Initially it's simple: I want to pass values from R to a C function built into a .o shared library via .C or .Call function. The C function should simply print the values passed in via printf.
Here's my .Call method:
.Call("test", as.integer(5), as.character("A"), as.character("string_test"))
And my C code:
#include <stdio.h>
void test(int integer, char character, char **str) {
printf("Integer: %i\nChar: %c\nString: %s\n", integer, character, *str);
}
But when I call the C function from R via console (RStudio crashes) with gdb enabled, I receive:
Integer: 1466480376
Char: �
Float: -100407552.000000
String:
***caught segfault ***
address 0x20000090, cause 'memory not mapped'
Traceback:
1: .Call("test", as.integer(5), as.character("A"), as.character("string_test"))
As if it were not enough, as we can see the values passed in are printed very strangely.
Details of what I did, step by step:
I built the .o shared library with gcc:
gcc -shared -o func_teste.o -fPIC func_teste.c
And prepared it for dynamic loading in R environment:
$ R CMD SHLIB func_teste.o
gcc -m64 -I/usr/include/R -DNDEBUG -I/usr/local/include -fpic -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -c func_teste.c -o func_teste.o
gcc -m64 -shared -L/usr/lib64/R/lib -Wl,-z,relro -specs=/usr/lib/rpm/redhat/redhat-hardened-ld -o func_teste.so func_teste.o -L/usr/lib64/R/lib -lR
And finally, inside R console, i ran:
>dyn.load('func_teste.o')
>.Call("test", as.integer(5), as.character("A"), as.character("string_test"))
Does anyone have idea why this is happening?
R offers two main functions for interfacing from C code (and hence C++ code, or any other language able to use a C interface):
- .C() is the older interface using int*, double*, ... and alike
- .Call() is the newer, more powerful interface using SEXP objects
Now, .Call() looks more complicated but it is so much more powerful as well as safer. There is near universal consensus that .C() should no longer be used (see various discussions on the r-devel list and other places).
The main downside with .Call() is that you need to learn how to pack and unpack your values. Or ... you cheat and let Rcpp do it for you. So with that, here is one-line solution of the OP's example:
> library(Rcpp)
> cppFunction("void mytest(int i, char c, std::string str) { printf(\"Integer: %i Char: %c String: %s\\n\", i, c, str.c_str()); }")
> mytest(42L, 'Q', "a boat")
Integer: 42 Char: Q String: a boat
>
I made the char* a string. Note that cppFunction() requires escaping of strings, you may want to look into sourceCpp() and packages for real work. The Rcpp documentation has details.
Don't as.character on "string_test".
Read more here: http://mazamascience.com/WorkingWithData/?p=1067
I recently asked this question about compiling multiple files in C so that a file main.c can reference a file modules.c. The answer ended up being to make the modules file into a header file and having main import it.
I have now been told that this is an incorrect way to do it, as C supports modular compilation. My Makefile is below, and this is supposedly supposed to be correct, but I receive errors for each function call in main.c -- warning: implicit declaration of function X.
What do I need to do to compile this correctly, with two .c files rather than a .c and .h file? The main.c file has a main() function that needs to be able to call the functions in modules.c.
Makefile:
#################################################################
# Variables
# -- allows C-source and assembly-source files mix. Again, the
# -- indented lines start with a TAB(^I) and not spaces..
#################################################################
CFLAGS = -g -Wall -Werror
LDFLAGS =
CC = gcc
LD = gcc
TARG = driver
OBJS = modules.o main.o
#################################################################
# Rules for make
#################################################################
$(TARG): $(OBJS)
$(LD) $(LDFLAGS) $(OBJS) -o $(TARG)
%.o: %.c %.s
$(CC) $(CFLAGS) -c $<
clean:
rm -f *.o *˜ $(TARG)
print:
pr -l60 Makefile modules.c main.c | lpr
#################################################################
# Dependencies -- none in this program
#################################################################
You've already gotten feedback about using GCC and Makefiles, and it's been noted that the typical way to accomplish your task would be two .c files and one .h file. But it's not required to have a .h file if you use function declarations (which is arguably simpler, just less maintainable and useful), as demonstrated by the following below example.
main.c:
void moduleFunc1(int); // extern keyword required for vars, not for functions
int main()
{
moduleFunc1(100);
return 0;
}
module.c:
#include <stdio.h>
void moduleFunc1(int value)
{
printf("%d\n", value);
}
To compile:
gcc main.c module.c
Edit: After having looked at the assignment you linked, my best guess is actually still that function declarations are what you are looking for. To quote from the assignment, under "Others", #7:
A function should be declared in the module/function where
it is called and not in global scope. Say A calls B and C does
not call it then B should be declared in A only.
In my example, the function declaration is in the module where it's called and seems to meet the A-B-C example. (The confusing part is the global scope comment, but I wouldn't say that the function declaration's scope is global. Observe that if you move the declaration below main(), for example, it messes things up. I haven't found something strictly authoritative for this point, though.)
Having read the assignment, could your instructor possibly mean the following?
main.c:
#include <stdio.h>
int main() {
int plus(int a, int b); /* declaration */
printf("%d ", plus(4, 5));
exit(0);
}
module.c:
int plus(int a, int b) {
return a + b;
}
gcc -Wall -Wextra main.c module.c
The thing is though, that plus() is available in the global namespace. So I am a bit lost.
Just an aside:
3. int next = 234;
printf("%6d ", next);
will print value of next, right justified in 6 columns
6. Use separate statements for declaration and initialization
of a variable as:
int xval;
xval = 100;
Do as I say, not as I do!
You can do this a few ways, but regardless of which you choose, if main.c calls functions from module.c, then main.c must #include a header which declares prototypes for those functions.
The first and simplest way is to just do this:
gcc -Wall -g main.c module.c -o myprogram
The second and more ornate way is to build module.c first as an object file. The primary purpose of this method is to save time when developing/debugging/compiling large programs with multiple parts -- rather than having to recompile the whole thing, you can just recompile the parts the have changed. It also allows you to easily mix and match parts. This is easiest to do with a makefile:
myprogram: main.c module.o
CC $(CFLAGS) main.c module.o -o myprogram
module.o:
CC $(CFLAGS) -c module.c
Notice the "myprogram" target from the makefile works with (prereq) module.o whereas the plain gcc method works with module.c.
If, as per your assignment, you can't use a header or global declarations, you can declare prototypes inside functions:
void somefunc () {
char *whatever (int x); // prototype
printf("%s\n", whatever(12));
}
Is fine, and presuming whatever() is defined somewhere, will work when you compile and run it.
We have some code in spatialite that looks like:
static int cmp_pt_coords (const void *p1, const void *p2)
{
....
}
static gaiaGeomCollPtr auxPolygNodes (gaiaGeomCollPtr geom)
{
....
/* sorting points by coords */
qsort (sorted, count, sizeof (gaiaPointPtr), cmp_pt_coords);
....
}
This is obviously simplified - the real code can be seen at
https://www.gaia-gis.it/fossil/libspatialite/artifact/fe1d6e12c2f98dff23f9df9372afc23f745b50df
The error that I'm getting from gcc (gcc version 4.6.1 (Ubuntu/Linaro 4.6.1-9ubuntu3)) is
/bin/bash ../../libtool --tag=CC --mode=compile gcc -DHAVE_CONFIG_H -I. -I../.. -g -Wall -Werror -fprofile-arcs -ftest-coverage -g -I../../src/headers -fvisibility=hidden -g -Wall -Werror -fprofile-arcs -ftest-coverage -g -MT libsplite_la-spatialite.lo -MD -MP -MF .deps/libsplite_la-spatialite.Tpo -c -o libsplite_la-spatialite.lo `test -f 'spatialite.c' || echo './'`spatialite.c
libtool: compile: gcc -DHAVE_CONFIG_H -I. -I../.. -g -Wall -Werror -fprofile-arcs -ftest-coverage -g -I../../src/headers -fvisibility=hidden -g -Wall -Werror -fprofile-arcs -ftest-coverage -g -MT libsplite_la-spatialite.lo -MD -MP -MF .deps/libsplite_la-spatialite.Tpo -c spatialite.c -fPIC -DPIC -o .libs/libsplite_la-spatialite.o
spatialite.c: In function 'auxPolygNodes':
spatialite.c:17843:5: error: passing argument 4 of 'qsort' from incompatible pointer type [-Werror]
/usr/include/stdlib.h:761:13: note: expected '__compar_fn_t' but argument is of type 'int (*)(void *, void *)'
cc1: all warnings being treated as errors
I've looked at some previous postings:
What are the parameters in this C qsort function call?
Warning when using qsort in C
However they don't really seem the same (or at least, the way I read the suggestions in those postings is what I think we're already doing here).
I can cast around this, using:
qsort (sorted, count, sizeof (gaiaPointPtr), (__compar_fn_t)cmp_pt_coords);
However I don't see why that should be necessary, and I'm worried about portability to other systems. It seems like the compiler is omitting the const-s from the arguments.
That cast is perfectly fine. GCC isn't smart enough to know that __compar_fn_t is
int (*)(const void *, const void *)
so it issues a warning.
However, __compar_fn_t is not portable -- so if you don't want to use it for casting, you should probably make GCC not warn about this using an appropriate compiler flag.
Or you can see whether __compar_fn_t is defined, and if not, define it yourself:
#ifndef __GNUC__
typedef int (*__compar_fn_t)(const void *, const void *);
#endif
The error probably comes from the visibility flag that you pass to the compiler. Your are saying that all functions in that compilation unit should be hidden. For gcc this changes the function API so your comparison function is then incompatible with the one expected by qsort.
You might want to deal with
#pragma visibility
or
__attribute__((__visibility(default)))
or similar for your comparison function.
The reason for the warning/error is that the GCC prototype of __compar_fn_t is:
typedef int (*__compar_fn_t)(__const void *, __const void );
and not:
typedef int (__compar_fn_t)(const void *, const void *);
Therefore, in order to solve the problem, simply define your function as:
static int cmp_pt_coords (__const void *p1, __const void *p2)