Changing array values in C produces "undefined reference to 'memset'" [closed] - arrays

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 days ago.
The community is reviewing whether to reopen this question as of 3 days ago.
Improve this question
I am initializing a 32-element array of 1s and 0s for the starting state for a Game of Life in C. When I use this line:
int board[] = {0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0};
there are no issues compiling. However, when I simply change the values in the array, and not the length or declaration of the array:
int board[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
the code does not compile, instead producing an "undefined reference to 'memset.'". Here is the error I get when compiling:
[ubuntu#swell-dipper:~/OS/assiqnment2/c-and-assemblvA] $ make
riscv64-unknown-elf-gcc -O -march=rv32im -mabi=ilp32 -g -c main.c -o main.o
riscv64-unknown-elf-gcc -O -march=rv32im -mabi=ilp32 -g -c lib.c -o lib.o
riscv64-unknown-elf-as -march=rv32im -g -c calc_val.s -o calc_val.o
riscv64-unknown-elf-gcc -O -march=rv32im -mabi.ilp32 -g -c simulation.c \
-o simulation.o
riscv64-unknown-elf-ld -nostdlib -o simulation -Map simulation.map \
-T demo.lds crt0.0 main.o lib.o calc_val.o simulation.o
riscv64-unknown-elf-ld: main.o: in function 'main':
/home/ubuntu/OS/assignment2/c-and-assembly/q2/main.c:23:
undefined reference to 'memset'
make: *** [Makefile:58: simulation] Error 1
How could the same exact code, simply with different values for the elements of the array, not be able to be compiled? I also never use anything in regards to memset in the code anywhere.
I have tried a few different values for the elements of the array, and it is on and off whether or not the code compiles.

You're running ld yourself. This is almost always a mistake. Use the gcc "compiler driver" to link, and remove -nostdlib and crt0.o from the linking command line, and the problem should go away.
What's happening is that the compiler has probably chosen to generate code for the second array initialization as if you had written
int board[32];
memset(board, 0, sizeof board);
board[K] = 1;
where K is the position of that single 1 in your array initializer. This is perfectly permissible; the C standard says that the compiler is allowed to generate calls to any C library function, even if they did not appear in the source code. You can make GCC less inclined to do this by using the -ffreestanding command line option, but it will not completely eliminate these "synthetic" calls. Section 2.1 of GCC's manual specifically points out that even in -ffreestanding mode, it may generate calls to memcpy, memmove, memset and memcmp.
GCC may also generate calls to functions in its own internal runtime library, whether or not it's in freestanding mode. These are used for things like arithmetic operations that the hardware doesn't provide instructions for.
When you use the compiler driver to link, the C library, the internal runtime library, and some "startup files" that handle stuff like C++ global constructors are automatically included in the link, so all this is invisible to you. Using ld bypasses that and exposes the fact that code generation needs these things even if you think it doesn't. You can in principle use gcc -v to find the names of all the extra implicit stuff and add back only the bits you need, but it's almost certainly easier to just use the compiler driver to link.

Related

Unit test with check library on MacOS 11.6.1: ld: library not found for -lcheck_pic

So I am trying to learn how to use the library check with a simple example on MacOS 11.6.1. For this I copied the code of Merlijn Sebrechts of the following question:
Using C unit testing framework Check without Autotools?
#include <check.h>
START_TEST (sanity_check)
{
fail_unless(5 == 5, "this should succeed");
fail_unless(6 == 5, "this should fail");
ck_assert_str_eq("asa", "asasdfasdf");
}
END_TEST
int main(void)
{
Suite *s1 = suite_create("Core");
TCase *tc1_1 = tcase_create("Core");
SRunner *sr = srunner_create(s1);
int nf;
suite_add_tcase(s1, tc1_1);
tcase_add_test(tc1_1, sanity_check);
srunner_run_all(sr, CK_ENV);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return nf == 0 ? 0 : 1;
}
When I execute the command in the terminal, I get the following error message:
$ gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
ld: library not found for -lcheck_pic
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I check that the library check is installed by compiling the file following file (test2.c) with gcc test2.c and did not get any error message. From this I assumed that the library is indeed installed
#include <check.h>
int main(){
int a;
return 0;
}
What am I doing wrong?
EDIT 1
Ok following the comment, I removed calling most of the libraries and run the following command:
gcc test.c -Wall -o test -lcheck
$ ./test
Running suite(s): Core
0%: Checks: 1, Failures: 1, Errors: 0
test.c:6:F:Core:sanity_check:0: this should fail
Is it correct? And I have to say frankly: I do not understand what the code is doing?
EDIT 2
After the new comment of Jason, I had to serially removed several libraries in order not get an error by build (namely lcheck_pic, lsubunit, lrt:
$ gcc test.c -Wall -o test -lcheck -pthread -lcheck_pic -pthread -lrt -lm -lsubunit
ld: library not found for -lcheck_pic
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lm -lsubunit
ld: library not found for -lsubunit
clang: error: linker command failed with exit code 1 (use -v to see invocation)
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lrt -lm -lsubunit
ld: library not found for -lrt
clang: error: linker command failed with exit code 1 (use -v to see invocation)
-v to see invocation)
$ gcc test.c -Wall -o test -lcheck -pthread -pthread -lm
... build successful ...
EDIT 3
In order to have every failure analyzed individually, I separated the check into difference instances as follows:
#include <check.h>
START_TEST (sanity_check1)
{
fail_unless(5 == 5, "this should succeed");
}
END_TEST
START_TEST (sanity_check2)
{
fail_unless(6 == 5, "this should fail");
}
END_TEST
START_TEST (sanity_check3)
{
ck_assert_str_eq("asa", "asasdfasdf");
}
END_TEST
int main(void)
{
Suite *s1 = suite_create("Core");
TCase *tc1_1 = tcase_create("Core");
SRunner *sr = srunner_create(s1);
int nf;
suite_add_tcase(s1, tc1_1);
tcase_add_test(tc1_1, sanity_check1);
tcase_add_test(tc1_1, sanity_check2);
tcase_add_test(tc1_1, sanity_check3);
srunner_run_all(sr, CK_ENV);
nf = srunner_ntests_failed(sr);
srunner_free(sr);
return nf == 0 ? 0 : 1;
}
and got the following output (displaying every failed test independently):
$ gcc script.c -Wall -o script -lcheck -pthread -pthread -lm
$ ./script
Running suite(s): Core
33%: Checks: 3, Failures: 2, Errors: 0
script.c:12:F:Core:sanity_check2:0: this should fail
script.c:18:F:Core:sanity_check3:0: Assertion '"asa" == "asasdfasdf"' failed: "asa" == "asa", "asasdfasdf" == "asasdfasdf"
The build solution was to remove -lcheck_pic.
Just expanding on the comment section...
Expecting 1 success and 1 failure... Is this correct?
Yes, that is correct. This is just an example of how to set up testing. In reality, you would never actually check 5 == 6. You would run portions of your program and check the state of whatever you are testing. Also, you should not need that #include <check.h> in the actual program code.
So think of something simple like an is_even function. You could do:
fail_unless(is_even(6), "failure");
This should not fail if your is_even function is correct. That may seem silly, but if later down the road you change the is_even function (or maybe a dependency of that function, this test may fail. That will let you know you need to review your last set of changes. You are essentially setting up automatic testing so you know right away if you broke something in your program.
It should also be noted that fail_unless has been deprecated. You should be using the functions provided here.
For more examples, here is a link to the test directory of a project of mine that uses libcheck.
Expansion on comment discussion
I linked to the tests directory in hopes that you would look at the C files in there... an example of how and why you would use check. For example, one of the more simple functions of the library is called sgetline which just means "safe getline". It will retrieve a single line from a file that can have either Linux (\n) or Windows (\r\n) line terminators and allocate a line buffer for you. Allow me to walk you through one of the tests for that function (from check_sgetline.c):
START_TEST(test_safegetline_long)
{
_file = fopen("test_long.txt", "r");
if (!_file) {
perror("test_long.txt");
exit(EXIT_FAILURE);
}
int ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_ptr_nonnull(buf);
ck_assert_str_eq(buf, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
ck_assert_uint_eq(linelen, strlen("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
ck_assert_int_eq(ret, 0);
ck_assert_uint_gt(buflen, BUFFER_FACTOR);
ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_int_eq(ret, EOF);
}
END_TEST
First, I open the file (test_long.txt is in that tests directory). Then, that FILE* is sent to sgetline along with a buffer, a buffer length and a line length (globals). sgetline can (and in this case will) modify these variables. The whole point of testing (and check) is to prove that my program does exactly what I "expect." In order to prove to myself that sgetline works as expected, I use the ck_* functions provided by check. So, here is what the checks are doing in English:
I would not EXPECT the buffer to be NULL as sgetline should be allocating it for me:
ck_assert_ptr_nonnull(buf);
I EXPECT this silly long string to be placed into buf:
ck_assert_str_eq(buf, "012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789");
I EXPECT linelen to be equal to the length of the string that was placed in buf:
ck_assert_uint_eq(linelen, strlen("012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"));
I EXPECT the return value of sgetline to be 0 (meaning success in this case):
ck_assert_int_eq(ret, 0);
I EXPECT the buflen to increase beyond a constant in the library BUFFER_FACTOR because the line is quite long (NOTE the _gt means greater than):
ck_assert_uint_gt(buflen, BUFFER_FACTOR);
Run sgetline again which should read the next line out of the file. I know that the file only has one line to begin with, so I EXPECT sgetline to return EOF.
ret = sgetline(_file, &buf, &buflen, &linelen);
ck_assert_int_eq(ret, EOF);
If any of these checks fail, I know I have a bug in sgetline.

gcc optimization impact on shared library operation

I have an own shared library, compiled and linked as below:
gcc -g -Wall -fpic -c -o cont.o cont.c
gcc -g -shared -o libcont.so cont.o -lrt
I have a program (nr) which uses this library:
gcc -g -Wall -I/include_path -c -o nr.o nr.c
gcc -L/shared_lib_path nr.o -lcont -o nr
One of the shared library's functions, if invoked, calls POSIX message sending (mq_send()) possibly which results an assertion error. strace ./nr says the following about this:
) = 1 (in [5])
mq_timedreceive(5, "\17\0ryName\0stester\0\t\0op\0srate\0\22\0ro"..., 2000, 0, NULL) = 76
mq_open("tester_asdf", O_WRONLY|O_NONBLOCK) = 6
writev(2, [{"Inconsistency detected by ld.so:"..., 33}, {"dl-lookup.c", 11}, {": ", 2}, {"167", 3}, {": ", 2}, {"check_match", 11}, {": ", 2}, {"Assertion `", 11}, {"version->filename == ((void *)0)"..., 79}, {"' failed!\n", 10}], 10Inconsistency detected by ld.so: dl-lookup.c: 167: check_match: Assertion `version->filename == ((void *)0) || ! _dl_name_match_p (version->filename, map)' failed!
) = 164
The very interesting thing is, that if I compile the program with any level of optimization other than the default (e.g., -O3), everything works fine:
gcc -g -Wall -O3 -I/include_path -c -o nr.o nr.c
gcc -L/shared_lib_path nr.o -lcont -o nr
In this case strace ./nr says:
) = 1 (in [5])
mq_timedreceive(5, "\17\0ryName\0stester\0\t\0op\0srate\0\22\0ro"..., 2000, 0, NULL) = 76
mq_open("tester_asdf", O_WRONLY|O_NONBLOCK) = 6
mq_timedsend(6, "\t\0op\0srate\0\22\0root\0scall_rating\0\t"..., 59, 0, NULL) = 0
mq_timedreceive(5, "\t\0op\0srate\0\22\0root\0scall_rating\0\t"..., 2000, 0, NULL) = -1 EAGAIN (Resource temporarily unavailable)
pselect6(6, [5], NULL, NULL, NULL, {~[INT ILL BUS FPE KILL SEGV ALRM TERM STOP RTMIN], 8}
Which is exactly that I would expect independently from the optimization level.
What could be the possible reason causing this?
The corresponding code snippet:
fprintf(stderr, "mqFd: %d, msg: %p, size: %d\n", (int)mqFd, msg, (int)size);
mq_send(mqFd, msg, size, 0);
fprintf prints just before the mq_send:
mqFd: 6, msg: 0x7ffdadef1820, size: 59
which is fine, but calling mq_send results the above detailed assertion.
I think this part from gcc man page, might be relevant to what you see:
-shared
Produce a shared object which can then be linked with other objects to form an executable.
Not all systems support this option. For predictable results, you must also specify the
same set of options used for compilation (-fpic, -fPIC, or model suboptions) when you
specify this linker option.[1]
This means, you need to add -fpic to the command line of the library creation.

Compiling Unix code on Mac

We were given course work to create the game Mine Sweeper. We are still early in the semester so this homework shouldn't be too difficult.
We were given header and source files that are to be used for the visual part of the program.
Main problem is that I can't compile these files on my Mac. Here is what I get:
$ gcc mineSweeper.c -I.
Undefined symbols for architecture x86_64:
"_colorPrint", referenced from:
_main in mineSweeper-4b9486.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
Also tried this:
$ gcc mineSweeper.c -I. -arch i386
Undefined symbols for architecture i386:
"_colorPrint", referenced from:
_main in mineSweeper-0938b1.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)
gcc version:
gcc --version
Configured with: --prefix=/Library/Developer/CommandLineTools/usr --with-gxx-include-dir=/usr/include/c++/4.2.1
Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn)
Target: x86_64-apple-darwin13.4.0
Thread model: posix
OSX version:
Software OS X 10.9.5 (13F34)
And finally the code we were provided with:
//colorPrint.h
//defines possible colors for the foreground color.
typedef enum
{
FG_Def = 0,
FG_Black = 30,
FG_Red,
FG_Green,
FG_Yellow,
FG_Blue,
FG_Magenta,
FG_Cyan,
FG_White
}fgColor;
//defines possible colors for the background color.
//BG_Def prints with the default background color of the terminal.
typedef enum
{
BG_Def = 0,
BG_Black = 40,
BG_Red,
BG_Green,
BG_Yellow,
BG_Blue,
BG_Magenta,
BG_Cyan,
BG_White
}bgColor;
//defines possible additional attributes for the color printing.
//normally, you would use ATT_Def.
typedef enum
{
ATT_Def = 0,
ATT_Bright = 1,
ATT_Underline = 4,
ATT_Reverse = 7,
ATT_Hidden = 8,
ATT_Scratch = 9
}attribute;
//clears the screen completely.
void clearScreen();
//prints a format string with its arguments (like printf!),
//in the specified foreground color, background color, and attribute.
void colorPrint(fgColor fg, bgColor bg, attribute att, char* format,...);
//colorPrint.c
#include <stdio.h>
#include <colorPrint.h>
#include <stdarg.h>
void clearScreen()
{
printf("\e[1;1H\e[2J");
}
void colorPrint(fgColor fg, bgColor bg, attribute att, char* format,...)
{
va_list args;
if(bg != BG_Def)
printf("\e[%d;%d;%dm",att,fg,bg);
else
printf("\e[%d;%dm",att,fg);
va_start (args, format);
vprintf(format, args);
va_end (args);
printf("\e[0m");
}
There is another header and code for receiving the char from user but I'm assuming linking it is irrelevant.
Any sort of help is welcome.. thanks in advance :)
PS. I also have a PC if it helps to switch to windows.
PPS. I'm keeping VirtualBox as a last resort.
You're trying to compile and link mineSweeper.c into a final executable on its own, but that file is not a complete program, it depends on a function defined in another file.
You either need to compile and link all the files in one step:
gcc mineSweep.c colourPrint.c
or compile each file separately and then link the objects:
gcc -c mineSweeper.c
gcc -c colorPrint.c
gcc mineSweeper.o colorPrint.o
I'm surprised your course didn't explain how to compile programs consisting of more than one file.
A simple makefile will ease the process:
mineSweeper: mineSweeper.o colorPrint.o
$(CC) $^ $(LDLIBS) -o $#

Problems with printf() on AVR in C with floating-point

I've been getting back into C, and I've been working on an 'academic' exercise to sharpen some old skills again. My project revolves around the rather simple process of generating sines. I started out just coding for x86 on the command line (Fedora Core 20) and everything worked fine. I then migrated the code to AVR, and I started learning a lot. For example, how to set up the UART as stdout. However, as sines are floating-point, I ran into problems using printf and sprintf.
The program generates 30 sines, and then prints the values to terminal. The text "Sine: " prints properly, but then I get question marks for the float. Replacing the variable with a constant had no effect.
The first thing I was suggested was if I had remembered the linker option for full floating point support - indeed I had forgotten. Again, adding this into my makefile had no effect.
I'm not sure of the policy here of copying and pasting code: should I paste it and my makefile here for inspection?
EDIT: Sorry for the long delay. I've done some more reading, including what the first answer links to. I had already read that reference before (the GNU one) and I have included the link in my Makefile, which is why I'm so confused. Here's my Makefile in all its glory:
P = sines
OBJ = sines.o
PROGRAMMER = buspirate
PORT = /dev/ttyUSB0
MCU_TARGET = atmega328p
AVRDUDE_TARGET = atmega328p
HZ = 16000000
DEFS =
LIBS = -lprintf_flt -lm
CC = avr-gcc
override CFLAGS = -g -DF_CPU=$(HZ) -Wall -O1 -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS= -Wl,-Map,$(P).map -u,vfprintf
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
all: $(P).elf lst text
$(P).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) -o $# $^ $(LIBS)
clean:
rm -rf *.hex *.bin *.map *~ sine*.csv *.o $(P).elf *.lst
lst: $(P).lst
%.lst: %.elf
$(OBJDUMP) -h -S $< > $#
text: hex bin
hex: $(P).hex
bin: $(P).bin
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $#
%.bin: %.elf
$(OBJCOPY) -j .text -j .data -O binary $< $#
install: $(P).hex
avrdude -p $(AVRDUDE_TARGET) -c $(PROGRAMMER) -P $(PORT) -v -U flash:w:$(P).hex
What I'm concerned about is that perhaps the linker arguments aren't in the correct order? From what I can tell, they are but...
I'm fairly sure my code itself is fine. If wanted, I can post it here as well.
Also, thanks for transferring my question over here. Didn't quite understand the difference between the two!
Here's the source code. It's being run on an ATmega328P. This current version is printing a constant as a debug, instead of the result from sinescalc(), even though I know that function is working (at least, it should be, I'm pretty sure I checked using avr-gdb at one point -- it definitely works on the command line, and also on an MSP430).
#include <avr/io.h>
//#include <util/delay.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
static int uart_putchar(char c, FILE *stream);
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
static int uart_putchar(char c, FILE *stream) {
if (c == '\n')
uart_putchar('\r', stream);
while(!(UCSR0A & (1<<UDRE0)));
UDR0 = c;
return 0;
}
void sinescalc(double *sinptr, int cycles, int size) {
double pi = acos(-1);
double step = ((pi * (cycles*2))/ size);
float temp;
double z = step;
int y;
for(y = 0; y<= size; y++) {
temp = sin(z); // calculate the current sine
*sinptr = (double)temp; // pass it into the array from main()
z += step; // add the step value to prepare for next sine
sinptr++; // should move the pointer by correct size of variable
}
}
int main(void) {
unsigned long _fosc = 16000000;
unsigned int _baud = 19200;
unsigned long _myubrr = _fosc/16/_baud-1;
unsigned int array_size = 256;
UBRR0L = (unsigned char)_myubrr;
UCSR0B = (1<<RXEN0)|(1<<TXEN0); //enable receiver and transmitter
stdout = &mystdout;
double sines[array_size];
double *sinepointer = sines; // set sinepointer to first element of sines array
sinescalc(sinepointer, 2, array_size); // calculate two cycles of sine, with 255 data points
int y;
//char msg[6] = ("Sine: ");
char output[40];
for(y = 0; y <= array_size; y++) {
sprintf(output, "Sine:\t %.6f", 1.354462);
printf(output);
printf("\n");
}
return 0;
}
This page states that to get the full printf() implementation, that supports printing floats, you should use:
-Wl,-u,vfprintf -lprintf_flt -lm
So I solved it. For those wondering, it really DOES come down to the order of arguments after -Wl. Here's the final makefile that seems to be working (so far, in a simulator):
P = sines
OBJ = sines.o
PROGRAMMER = buspirate
PORT = /dev/ttyUSB0
MCU_TARGET = atmega328p
AVRDUDE_TARGET = atmega328p
HZ = 16000000
DEFS =
LIBS = -lprintf_flt -lm
CC = avr-gcc
override CFLAGS = -g -DF_CPU=$(HZ) -Wall -O2 -mmcu=$(MCU_TARGET) $(DEFS)
override LDFLAGS= -Wl,-u,vfprintf,-Map,$(P).map
OBJCOPY = avr-objcopy
OBJDUMP = avr-objdump
all: $(P).elf lst text
$(P).elf: $(OBJ)
$(CC) $(CFLAGS) $(LDFLAGS) $(LIBS) -o $# $^
I thought that I had tried that order before, and it threw an error. What I think I did wrong before was omit the comma after vfprintf. Also, the suggestion from another website of putting the -u,vfprintf AFTER the LDFLAGS (and after the -o section) was also clearly incorrect.
Edit from 2018: Recent versions of GCC seem to require the libraries to come as the last argument, no matter what other arguments there are. If you are having problems compiling (I'm not sure what versions of gcc/avr-gcc are being distributed by the various distros) and you are getting a bunch of "implicit declaration of x function" errors, it's because your library arguments are in the wrong spot. This just bit me recently, and I haven't seen any information on why this change happened, or which versions are affected.
Why it has to go in exactly that spot, I don't know yet. Perhaps someone can shed some light on it? I can't believe the answer was as inane as this. I just started moving things around until I hit on this. However, after looking at the GNU documentation again, they show the -Wl, directly before the -u,vfprintf. What threw me off was the presence of the -Map,$(P).map, which I thought had to go directly after -Wl as well. It seems like the -lprintf_flt -lm can come afterwards. I know that -lm is the option to link in the GNU math libraries, which is important for floating point math, obviously. I also understand what the other two options do (link in the correct version of the stream functions with floating-point support compiled in). But as I said before, perhaps someone can point me (and others) to a resource regarding hierarchy of gcc linker options? This problem has been dogging me for a week, and nobody was able to just point out that the -Map could come afterwards, but still needed a comma in between. I might try flipping around the -Map and the -u options, still with their commas, to see if it's THAT hierarchically important...
It isn't. Just changed it to -Wl,-Map,sines.map,-u,vfprintf and t still works with no problem. So the answer had to do with commas, which I take it means that all linker options need to be attached with commas? Why doesn't -lm need to be there as well? I'm a littl baffled, but relieved that it's working. Now I just need to try it on the hardware, though I'm pretty sure it'll work just fine.
Thanks everyone, for your help! This has been a great introduction to Stack Overflow (and all the Stacks) and I really hope that I can learn a lot, and contribute to this community. I've been carefully re-reading all the articles about asking good questions, and how the reputation and voting system works, so hopefully I get it right and I don't piss anyone off :)
Cheers!!
You can convert float (can be double, but in avr-gcc till v9 is implemented the same as float) to string prior printing it, and you can go without linker alterations by ie:
float in_volt = temp/1024.0*5.0;
char in_volt_string[8];
dtostrf(in_volt, 6, 4, in_volt_string);
That solved it for me in AVR Studio 4 with Atmega32. Then was put to lcd and tera term without problems.

passing pointer to int array into template function

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?

Resources