With the header file (UDPRBPlib.h) and the implementation file (UDPRBPlib.c) I keep getting errors of multiple definitions for global variables and all of my functions shown below:
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:14: multiple definition of `set'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:14: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:15: multiple definition of `get'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:15: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:16: multiple definition of `run'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:16: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:17: multiple definition of `stop'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:17: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o:/home/UDPRBPlib.h:26: multiple definition of `server_struct_length'; /tmp/ccuctEs0.o:/home/UDPRBPlib.h:26: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPCurrentConvert':
/home/UDPRBPlib.c:4: multiple definition of `RBPCurrentConvert'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:4: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `sendUDPMsg':
/home/UDPRBPlib.c:12: multiple definition of `sendUDPMsg'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:12: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `UDPinit':
/home/UDPRBPlib.c:54: multiple definition of `UDPinit'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:54: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPSendSetpt':
/home/UDPRBPlib.c:76: multiple definition of `RBPSendSetpt'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:76: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `FTFToggle':
/home/UDPRBPlib.c:106: multiple definition of `FTFToggle'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:106: first defined here
/usr/bin/ld: /tmp/ccTq4sS2.o: in function `RBPSetRemote':
/home/UDPRBPlib.c:122: multiple definition of `RBPSetRemote'; /tmp/ccuctEs0.o:/home/UDPRBPlib.c:122: first defined here
collect2: error: ld returned 1 exit status
Header file (UDPRBPlib.h):
#ifndef UDPRBPLIB_H
#define UDPRBPLIB_H
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <stdint.h>
#include <unistd.h>
uint8_t client_message[1];
uint8_t set = 0x73;
uint8_t get = 0x67;
uint8_t run = 0x18;
uint8_t stop = 0x02;
// INIT
//#define DEBUGMODE 1
int socket_desc;
struct sockaddr_in server_addr;
char server_message[60];
// SEND MSG
int server_struct_length = sizeof(server_addr);
struct setpt{
uint16_t setptValue; // thing we're sending // [9] and [10] in RBPSendSetpt function
uint8_t signflag; // RBP only takes positive numbers, the sign is to be communication in terms of charge and discharge signified by this flag
uint8_t cktNum;
int mode; // 1 for cc and 0 for cv
int runOrStop; // 1 for run; 0 for stop
int setOrGet; // 1 for set; 0 for get
};
uint16_t RBPCurrentConvert(float x);
int sendUDPMsg();
int UDPinit();
void RBPSendSetpt(const struct setpt tmp);
void FTFToggle(const struct setpt tmp);
void RBPSetRemote(const struct setpt tmp);
#endif
Implementation file (UDPRBPlib.c):
#include "UDPRBPlib.h"
// will convert x to the proper format
uint16_t RBPCurrentConvert(float x){
x = fabs(x);
x *= 100;
x = roundf(x);
uint16_t y = x;
return y;
}
int sendUDPMsg(){
int length = sizeof(client_message)/sizeof(client_message[0]);
#ifdef DEBUGMODE
printf("Sending message:");
printf("\n");
#endif
for(uint16_t i=0; i<sizeof(client_message); i ){
printf("0x%X\t", client_message[i]);
if ((i 1) % 15 == 0) printf("\n");
}
// Send the message to server:
if(sendto(socket_desc, client_message, sizeof(client_message), 0, (struct sockaddr*)&server_addr, server_struct_length) < 0){
printf("Unable to send message\n");
return -1;
}
// Receive the server's response:
if(recvfrom(socket_desc, server_message, sizeof(server_message), 0, (struct sockaddr*)&server_addr, &server_struct_length) < 0){
printf("Error while receiving server's msg\n");
return -1;
}
printf("\nReceived message:");
for(uint16_t i=0; i<sizeof(server_message); i ){
if(i == 0)
printf("\n");
printf("0x%X\t", server_message[i]);
}
printf("\n");
// error check: see if what was returned was the same as what was sent
for(int i = 0; i < length; i ){
if(server_message[i] != client_message[i])
printf("Error in server message at index %d\n", i);
}
// Close the socket:
close(socket_desc);
return 0;
}
int UDPinit(){
// Clean buffers:
memset(server_message, '\0', sizeof(server_message)); //init
//memset(client_message, '\0', sizeof(client_message));
// Create socket: in init
socket_desc = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
if(socket_desc < 0){
printf("Error while creating socket\n");
return -1;
}
printf("Socket created successfully\n");
// Set port and IP: init
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(36112);
server_addr.sin_addr.s_addr = inet_addr("169.254.0.1");
return 0;
}
// assembles the message and returns a pointer to the message
void RBPSendSetpt(const struct setpt tmp){
client_message[19];
client_message[0] = 0x01; // Rack Control Address
client_message[1] = tmp.cktNum;
client_message[2] = 0x43; // mandatory
client_message[3] = 0x53; // mandatory
if(tmp.setOrGet == 1)
client_message[4] = set;
else if(tmp.setOrGet == 0)
client_message[4] = get;
client_message[7] = 0x00; // current
client_message[8] = 0x00;
sendUDPMsg();
return;
}
// assemles the message in run OR stop state
void FTFToggle(const struct setpt tmp){
client_message[5];
client_message[0] = 0x01;
client_message[1] = tmp.cktNum;
client_message[2] = 0x4C;
client_message[3] = 0x52;
if(tmp.runOrStop == 1)
client_message[4] = run;
else if(tmp.runOrStop == 0)
client_message[4] = stop;
sendUDPMsg();
return;
}
// assemles the message
void RBPSetRemote(const struct setpt tmp){
client_message[6];
client_message[0] = 0x01;
client_message[1] = tmp.cktNum;
client_message[2] = 0x4C;
client_message[3] = 0x30;
if(tmp.setOrGet == 1)
client_message[4] = set;
else if(tmp.setOrGet == 0)
client_message[4] = get;
client_message[5] = 0x01;
sendUDPMsg();
return;
}
If I put all the code in one file, it seems to run correctly, but when the code is in two different files, I get the above errors. I suspect there is something wrong with my headers in the respective files, but nothing I've tried has worked.
CodePudding user response:
The problem is that you're defining variables (e.g. uint8_t get = 0x67;
) in your .h
file, which means that you're defining those variables in every .c
file that #include
's that .h
file; hence the "multiple definition" errors.
To avoid that, you'll either need to change those definitions to declarations (e.g. extern uint8_t get;
) in your .h
file, and then a separate uint8_t get = 0x67;
in exactly one .c
file), or if they are intended to be constants, you could replace them with macros (e.g. #define get 0x67
, although I'd strongly recommend a less generic name in that case, e.g. #define MY_PROGRAM_CONSTANT_GET 0x67
, to avoid accidentally treading on other code's use of the same string.
CodePudding user response:
You have these lines in the header:
int socket_desc;
struct sockaddr_in server_addr;
char server_message[60];
Those are variable definitions. Every file that includes the header defines those variables. When you link two such files, the symbols are multiply defined.
Declare variables in headers — with extern
:
extern int socket_desc;
extern struct sockaddr_in server_addr;
extern char server_message[60];
Note you can't use an initializer.
Once upon a while ago, in versions of GCC before GCC 10, the default behaviour was to make such definitions into 'common' variables, and those could be 'multiply defined'. The 'common' is named after Fortran COMMON blocks. With GCC 10 and later, the default behaviour is to make those non-common definitions. If you're really stuck with ancient code that you can't modify, you may have to override the modern default option -fno-common
with an explicit -fcommon
in the build process. It isn't recommended. The standard always said that this was incorrect, but recognized it as a common extension, with the double entendre fully intended.
See also How do I use extern
to share variables between source files?
Incidentally, note that unless you're using C23 (or later), the lines:
int sendUDPMsg();
int UDPinit();
declare the functions sendUDPMsg()
and UPDinit()
, but they do do not provide prototypes for the functions — so they can be called with any sequence of arguments. If your functions take no arguments, say so explicitly:
int sendUDPMsg(void);
int UDPinit(void);