Автор Тема: undefined reference to `round'  (Прочетена 2281 пъти)

0 Потребители и 1 Гост преглежда(т) тази тема.

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
undefined reference to `round'
« -: 20 Октомври 2016, 03:11:04 »
Каква е причината да хвърчат тези грешки при компилиране:

Код: C
  1. #include <stdio.h>
  2. #include <math.h>
  3.  int main()
  4. {
  5.        float i=5.4, j=5.6;
  6.        printf("round of  %f is  %f\n", i, round(i));
  7.        printf("round of  %f is  %f\n", j, round(j));
  8.        return 0;
  9. }
  10.  
  11.  

Цитат
dimt@dimt-Satellite-L670 ~/arduino $ gcc loop.c -o loop
/tmp/ccaj7ebD.o: In function `main':
loop.c:(.text+0x28): undefined reference to `round'
loop.c:(.text+0x4a): undefined reference to `round'
collect2: error: ld returned 1 exit status
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html

kjufte

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 1
  • -Получени: 51
  • Публикации: 308
Re: undefined reference to `round'
« Отговор #1 -: 20 Октомври 2016, 07:08:13 »
като компилираш трябва да линкнеш math библиотеката

Код: Text
  1. gcc loop.c -lm -o loop


Малко разяснение към темата.

Слагайки #include <math.h>, ти казваш на компайлера, че искаш да ползваш някоя от функциите, които са декларирани в този хедър файл.
В случая във math.h има ред подобен на този:
Код: C
  1. extern double round _PARAMS((double));

Та след като си инклуднал файла и напишеш round(25.7), компайлера знае, че има такава функция дефинирана, която се казва round връща double и взема като аргумент double.
Как обаче точно става тази магия в този момент не е ясно и няма значение.

След като си компилираш *.c файловете до обекти *.о, линкъра се опитва някак си да ги свърже. При тази операция ще види, че има изпозвана някаква функция round и ще се опита да намери дефиницията (не декларацията!) на тази функцията. Тя се намира примерно във файла библиотека libm.a, който се намира някъде в папката на toolchain-а дето ползваш. Библиотеките при C имат разширение ".а" и са един вид архив съдържащ прекомпилирани object файлове. Един от тези обекти вътре съдържа дефиницията на round.

Та за да знае линкъра, че искаш да ползваш някоя от тези библиотеки, ти трябва изрично да му я посочиш.
« Последна редакция: 20 Октомври 2016, 08:21:10 от kjufte »

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
Re: undefined reference to `round'
« Отговор #2 -: 20 Октомври 2016, 14:20:41 »
Аха...стана ми ясно вече :)

2-ри въпрос.

Имам следният код който има за задача да взима аналоговият сигнал от А0 порта и да го преобразува в дигитален, както и да върне изхода в терминала на компа ми. Кода работи и round() функцията също, само дето резултата е една голяма питанка  ??? Имам усещането, че нашият прочут експерт от научиМе с име Питанката е хакнал компа ми :)

Код: C
  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <avr/io.h>
  4. #include <util/delay.h>
  5. #define NUM_READINGS 10
  6. #define USART_BAUDRATE 9600
  7. #define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
  8. #define PORT_ON(port,pin) port |= (1<<pin)
  9. #define PORT_OFF(port,pin) port &= ~(1<<pin)
  10.  
  11. void USART0Init(void)
  12. {
  13. // Set baud rate
  14. UBRR0H = (uint8_t)(UBRR_VALUE>>8);
  15. UBRR0L = (uint8_t)UBRR_VALUE;
  16. // Set frame format to 8 data bits, no parity, 1 stop bit
  17. UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
  18. //enable transmission and reception
  19. UCSR0B |= (1<<RXEN0)|(1<<TXEN0);
  20. }
  21.  
  22. int USART0SendByte(char u8Data, FILE *stream)
  23. {
  24.    if(u8Data == '\n')
  25.    {
  26.         USART0SendByte('\r', stream);
  27.    }
  28. //wait while previous byte is completed
  29. while(!(UCSR0A&(1<<UDRE0))){};
  30. // Transmit data
  31. UDR0 = u8Data;
  32. return 0;
  33. }
  34.  
  35. //set stream pointer
  36. FILE usart0_str = FDEV_SETUP_STREAM(USART0SendByte, NULL, _FDEV_SETUP_WRITE);
  37.  
  38. void InitADC()
  39. {
  40.     // Select Vref=AVcc
  41.     ADMUX |= (1<<REFS0);
  42.     //set prescaller to 128 and enable ADC
  43.     ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);    
  44. }
  45.  
  46. uint16_t ReadADC(uint8_t ADCchannel)
  47. {
  48.     //select ADC channel with safety mask
  49.     ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
  50.     //single conversion mode
  51.     ADCSRA |= (1<<ADSC);
  52.     // wait until ADC conversion is complete
  53.     while( ADCSRA & (1<<ADSC) );
  54.  
  55.     return ADC;
  56. }
  57.  
  58. /*
  59. int ReturnAVG(int r, int n) {
  60.  
  61. int values[10];
  62.  
  63. int i,j;
  64.  
  65. int  total = 0;
  66.  
  67. float average;
  68.  
  69. for (i = 0; i < n; i++) {
  70.  
  71.   values[i] = r;
  72.   printf("%d\n", values[i]);
  73.   _delay_ms(500);
  74.  
  75.  }
  76.  
  77.  for (j = 0; j < n; j++) {
  78.  
  79.   total = total + values[j];
  80.  
  81. }
  82. average = total / (float) n;
  83.    
  84. //return(round(average));
  85.  
  86. return total;
  87.    
  88. }
  89. */
  90. int main() {
  91.  
  92. uint16_t A0;
  93.  
  94. uint16_t values[10];
  95.  
  96. uint16_t total = 0;
  97.  
  98. uint16_t i,j;
  99.  
  100. float average;
  101.  
  102. DDRB=0xff; // Set Port B as Output
  103.  
  104. PORTB = 0x00;
  105.  
  106. //initialize ADC
  107. InitADC();
  108. //Initialize USART0
  109. USART0Init();
  110.  
  111. //assign our stream to standard I/O streams
  112. stdout=&usart0_str;
  113.  
  114. while(1)
  115. {
  116.  
  117.     //read 10 values of A0 and recalculating them to mv
  118.       for( i = 0; i < 10; i++) {
  119.       A0 = ReadADC(0);
  120.       values[i] = A0;
  121.       printf("Current %d\n", values[i]);
  122.       _delay_ms(500);    
  123.     }
  124.          
  125.  
  126.   for(j = 0; j < 10; j++) {
  127.     total = total + values[j];
  128.    }
  129.  
  130.    average = total / (float) NUM_READINGS;
  131.  
  132.    //send the total and avg reading in millivolts to terminal
  133.    printf("Total: %d\n",total);
  134.    printf("Average %f\n", average);
  135.  
  136.    // reset total to 0
  137.    total = 0;
  138.  
  139.    if(round(average) > 152) {
  140.  
  141.    PORT_ON(PORTB,0);
  142.    }
  143.     else
  144.    {
  145.    PORT_OFF(PORTB,0);
  146.    }
  147.   }
  148. }
  149.  
 

Изхода е:

Цитат
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 144
Current 145
Total: 1441
Average ?
Current 145
Current 145
Current 145
Current 146
Current 147
Current 147
Current 147
Current 146
Current 147
Current 146
Total: 1461
Average ?

Имам и още едно питане,  как да вкарам  кодa от main() в отделна функция. Написах ReturnAVG, но взема само първият резултат копирайки го 10 пъти. 
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html

kjufte

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 1
  • -Получени: 51
  • Публикации: 308
Re: undefined reference to `round'
« Отговор #3 -: 20 Октомври 2016, 19:49:09 »
Ако хвърлиш едно око на документацията на avr-libc, или по-точно на функцията използвана от printf за форматиран изход vfprintf ще прочетеш следното:

Цитат на: http://nongnu.org/
Since the full implementation of all the mentioned features becomes fairly large, three different flavours of vfprintf() can be selected using linker options. The default vfprintf() implements all the mentioned functionality except floating point conversions. A minimized version of vfprintf() is available that only implements the very basic integer and string conversion facilities, but only the # additional option can be specified using conversion flags (these flags are parsed correctly from the format specification, but then simply ignored). This version can be requested using the following compiler options:

Код: Text
  1. -Wl,-u,vfprintf -lprintf_min
   
If the full functionality including the floating point conversions is required, the following options should be used:

Код: Text
  1. -Wl,-u,vfprintf -lprintf_flt -lm

Общо взето при toolchain-ите за uC, float почти винаги не е включен за printf по подразбиране. Това включва естествено и sprintf и всички функции, които опират до vfprintf.

Та или ползваш горепосочените флагчета при линкване, или както много често се прави си пишеш някаква workaround функция, която разделя стойността на два int-а (преди запетая и след запетая -> modulo).
Втория вариант има предимството, че намаля значително размера на кода, което при микроконтролерите е от голямо значение.

За втората питанка направо ти едитнах малко кода с inline коментари. Кода не е тестван, но чак толкова няма какво да е объркано. Ако има въпроси питай :)

Код: C
  1. #include <stdio.h>
  2. #include <math.h>
  3. #include <avr/io.h>
  4. #include <util/delay.h>
  5.  
  6. #define NUM_READINGS 10
  7. #define USART_BAUDRATE 9600
  8. #define ADC_CHANNEL 0
  9.  
  10. #define UBRR_VALUE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
  11. #define PORT_ON(port,pin) port |= (1<<pin)
  12. #define PORT_OFF(port,pin) port &= ~(1<<pin)
  13.  
  14.  
  15.  
  16. // първо декларираш всички функции
  17. void USART0Init(void);
  18. void USART0SendByte(char u8Data, FILE *stream);
  19. void InitADC(void);
  20. uint16_t ReadADC(uint8_t ADCchannel);
  21. float ReadAndReturnAVG(uint8_t channel,  uint16_t *values, int sizeOfValues);
  22.  
  23. // сега идват дефинициите на функциите
  24. void USART0Init(void)
  25. {
  26.     // Set baud rate
  27.     UBRR0H = (uint8_t)(UBRR_VALUE>>8);
  28.     UBRR0L = (uint8_t)UBRR_VALUE;
  29.     // Set frame format to 8 data bits, no parity, 1 stop bit
  30.     UCSR0C |= (1<<UCSZ01)|(1<<UCSZ00);
  31.     //enable transmission and reception
  32.     UCSR0B |= (1<<RXEN0)|(1<<TXEN0);
  33. }
  34.  
  35. // функция, която винаги връща 0 няма нужда да връща нищо
  36. // за това сменяме на void
  37. void USART0SendByte(char u8Data, FILE *stream)
  38. {
  39.     if(u8Data == '\n')
  40.     {
  41.         USART0SendByte('\r', stream);
  42.     }
  43.     //wait while previous byte is completed
  44.     while(!(UCSR0A&(1<<UDRE0))){};
  45.     // Transmit data
  46.     UDR0 = u8Data;
  47. }
  48.  
  49. //set stream pointer
  50. FILE usart0_str = FDEV_SETUP_STREAM(USART0SendByte, NULL, _FDEV_SETUP_WRITE);
  51.  
  52. void InitADC(void)
  53. {
  54.     // Select Vref=AVcc
  55.     ADMUX |= (1<<REFS0);
  56.     //set prescaller to 128 and enable ADC
  57.     ADCSRA |= (1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADEN);    
  58. }
  59.  
  60.  
  61. uint16_t ReadADC(uint8_t ADCchannel)
  62. {
  63.     //select ADC channel with safety mask
  64.     ADMUX = (ADMUX & 0xF0) | (ADCchannel & 0x0F);
  65.     //single conversion mode
  66.     ADCSRA |= (1<<ADSC);
  67.     // wait until ADC conversion is complete
  68.     while( ADCSRA & (1<<ADSC) );
  69.    
  70.     return ADC;
  71. }
  72.  
  73. /*
  74.  * Фунцкията приема като първи параметър канала от който ще чете
  75.  * Вторият параметър е указател към масива, в който ще запишем стойностите (uint16_t *values)
  76.  * Tъй като ReadADC ни връща uint16_t, то и стойностите в масива ще са от този тип.
  77.  * Накрая катваме на функцията колко голям е масива,който и подаваме, защото това при
  78.  * 'C'  не може да се определи по време на изпълнение на програмата
  79.  */
  80. float ReadAndReturnAVG(uint8_t channel,  uint16_t *values, int sizeOfValues) {
  81.     int i = 0;
  82.     int  total = 0;
  83.     float average = 0.0f;
  84.  
  85.     for (i = 0; i < sizeOfValues; i++) {
  86.         values[i] = ReadADC(channel); // тука може да ползваме функцията ReadADC,защото
  87.                                       // тя вече е декларирана най-отгоре и е позната
  88.         total = total + values[j];    // няма нужда от екстра loop за сбора
  89.         printf("%d\n", values[i]);
  90.         _delay_ms(500);
  91.     }
  92.  
  93.     average = (float)total / (float)sizeOfValues;
  94.  
  95.     return average;
  96. }
  97.  
  98.  
  99. int main() {
  100.     DDRB = 0xff; // Set Port B as Output
  101.     PORTB = 0x00;
  102.    
  103.     //initialize ADC
  104.     InitADC();
  105.     //Initialize USART0
  106.     USART0Init();
  107.    
  108.     //assign our stream to standard I/O streams
  109.     stdout = &usart0_str;
  110.  
  111.     uint16_t values[NUM_READINGS] = {0};
  112.     float average = 0.0f;
  113.    
  114.     while(1)
  115.     {
  116.         average = ReadAndReturnAVG(ADC_CHANNEL, values, NUM_READINGS);
  117.         printf("Average: %d\n", (int)(round(average))); // кастваш закръглената стойност към int
  118.                                                         // и си спестяваш линкване на float за printf
  119.    
  120. /**
  121.         // ако искаш може да изкараш всички стойности от последното четене
  122.         // Те са запаметени в масива, който подаваме на функцията
  123.         printf("Readings {\n");
  124.         int j = 0;
  125.         for(j = 0; j < NUM_READINGS; j++) {
  126.             printf("   [%d] %d\n", j, values[j]);
  127.         }
  128.         printf("}\n\n");
  129. */
  130.     }
  131. }
« Последна редакция: 20 Октомври 2016, 21:09:06 от kjufte »

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
Re: undefined reference to `round'
« Отговор #4 -: 20 Октомври 2016, 20:31:32 »
Thanks buddy :) Оценям труда / помоща ти и то много, просто да знаеш. Ще разгледам кода ти по-подробно довечера и ще питам, ако има нещо неясно за мен ;)

Taзи стойност (141.6 ) ще бъде закръглена към 142, а тази към ( 141.4) към 141 нали? 
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html

kjufte

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 1
  • -Получени: 51
  • Публикации: 308
Re: undefined reference to `round'
« Отговор #5 -: 20 Октомври 2016, 21:08:19 »
Е той кода си е твоят. Само малко е доокрасен.
Колкото до round-фунцкията, не мога да ти кажа със сигурност, но това бих очаквал и аз.
Ако стойността след заптаята не те вълнува няма нужда да правиш такива гимнастики. Без math.h и round направо кастваш към int и всичко след запетаята изчезва.
« Последна редакция: 20 Октомври 2016, 21:09:52 от kjufte »

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
Re: undefined reference to `round'
« Отговор #6 -: 20 Октомври 2016, 21:27:54 »
Е той кода си е твоят. Само малко е доокрасен.
Колкото до round-фунцкията, не мога да ти кажа със сигурност, но това бих очаквал и аз.
Ако стойността след заптаята не те вълнува няма нужда да правиш такива гимнастики. Без math.h и round направо кастваш към int и всичко след запетаята изчезва.
Всичко е наред.Точно това което очаквам е  :)
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
Re: undefined reference to `round'
« Отговор #7 -: 20 Октомври 2016, 21:30:20 »
Още нещо неясно за мен.Каква е разликата м/у uint16_t / uint8_t и int?
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html

kjufte

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 1
  • -Получени: 51
  • Публикации: 308
Re: undefined reference to `round'
« Отговор #8 -: 20 Октомври 2016, 21:44:51 »
uint16_t == unsigned int16_t == 16 битов int без знак. Т.е 2 байта интиджър със стойност между 0 и (2^16 - 1) == 65535
uint8_t  == unsigned int8_t == 8 битов int без знак.  Т.е 1 байт интиджър със стойност между 0 и (2^8 - 1) == 255
A колко бита/байта е int зависи от платформата  на която се намираш. Стандарта казва само че int трябва да е минимум 16 бита. Може да е 32 може и да е 64. Може да го провериш с един

Код: C
  1. printf("size of int = %u\n", sizeof(int));
« Последна редакция: 20 Октомври 2016, 22:21:35 от kjufte »

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
Re: undefined reference to `round'
« Отговор #9 -: 21 Октомври 2016, 00:41:41 »
Тези uint8_t / uint16_t стандартни ли са в C или се ползват само в AVR?
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html

kjufte

  • Sr. Member
  • ****
  • Благодарности
  • -Казани: 1
  • -Получени: 51
  • Публикации: 308
Re: undefined reference to `round'
« Отговор #10 -: 21 Октомври 2016, 16:14:15 »
Може да ги ползваш не само на микроконтролери като инклуднеш stdint.h.

Кaто се пишат десктоп приложения обикновено не се обръща внимание на такива неща. Но като пишеш за устройства с ограничени ресурси и знаеш, че по всяко време може stack-а да ти oveflow-не, ще се замислиш дали да обявиш масив от 500 int-а, който може би ще заеме 2000 или повече байта, или масив от 500 uint16_t/int16_t, който ще заеме точно 1000 байта.

jazzman

  • Hero Member
  • *****
  • Благодарности
  • -Казани: 25
  • -Получени: 190
  • Публикации: 3624
Re: undefined reference to `round'
« Отговор #11 -: 24 Октомври 2016, 20:16:02 »
Аха ...  ясно. Кода работи прекрасно за сега, включва / изключва всичко което съм задал като параметри. От другата седмица температурите ще се занижат значително при нас и ще видя как и хардуера си свърши работата.  Мерси за помоща ;) 
Java is to Javascript as fun is to funeral.

http://nau4i.me/forum/index.php/topic,15129.0.html