I've been running into a compiler warning:
version.h:47: warning: (1478) initial value for "_svn_string_revision" differs to that in version.h:47
the corresponding version.h file looks like this:
#ifndef _VERSION_H_
#define _VERSION_H_
#define SVN_REVISION_NUMBER 31
const char *svn_string_revision = "31"; // line 47
#endif //_VERSION_H_
Usage:
main.c:
#include "version.h"
// I do not use svn_string_revision here.
// I only use SVN_REVISION_NUMBER
#pragma config IDLOC3=SVN_REVISION_NUMBER
otherfile.c:
#include "version.h"
// still no usage of svn_string_revision, only this:
EUSART_Write(SVN_REVISION_NUMBER);
So far this is descriptive and clear. I assume the problem is that the const char string is defined in a header file, which gets included in more than one source code file. So the compiler sees more than one "svn_string_revision" variable and treats it as redeclaration. But normally the value should be always the same. My version.h file is an auto generated file which gets regenerated prior to every build.
Has somebody encountered this before, and how can I handle that?
The clean approach would be to use a version.h file complemented with a version.c, where the header declares
extern const char *svn_string_revision;
and the source
const char *svn_string_revision = "31";
But this would require me to rewrite the automated code generation, which I would like to avoid.
Long story short, my questions are:
Is my understanding of the warning correct?
How can I avoid those warnings gracefully, given that I don't want to split up version.h into a .c and .h file
First solution :
static const char *svn_string_revision = "31";
The static will make the variable local to each C file, so no conflict can occur. Since it is a read only constant it should be fine. However, this means there will be many copies of the variable in the program. A good compiler can optimize this, but in my experience, I'm not sure XC8 will do that.
Second solution, probably better :
#define SVN_REVISION_NUMBER 31
#define STRINGIFY(s) #s
extern const char *svn_string_revision;
// in version.c
const char *svn_string_revision = STRINGIFY(SVN_REVISION_NUMBER);
Or just :
#define SVN_REVISION_NUMBER 31
#define VERSION_STRING "31"
extern const char *svn_string_revision;
// in version.c
const char *svn_string_revision = VERSION_STRING;
You could also just remove svn_string_revision and use VERSION_STRING instead, but you should check before that XC8 doesn't create many copies of the string.
Related
I have a header file , "temp.h" ,and several ".c" files which has "#include <temp.h>" header statements in each of them. And I define a global static char array in "temp.h" file as follows:
temp.h
static char buffer[1000]={'A','B','C','\0'};
main.c
...
#include <temp.h>
int main()
{
strcpy(buffer,"xyz");
printf("\nBuffer : %s",buffer);
func();
return 0;
}
other.c
...
#include <temp.h>
int func()
{
printf("\nInside func(), buffer : %s",buffer);
return 0;
}
and I compile all files with following command:
gcc -o output.o main.c other.c
And I get no errors... and when run the "output.o" program ,
I expect a result like this:
Buffer : xyz // Buffer was intentionally changed inside main
Inside func(), buffer : xyz
but I get:
Buffer : xyz // Buffer was intentionally changed inside main
Inside func(), buffer : ABC // doesn't get updated buffer content- why?
Why when I change the contents of a "(supposedly)global" static char array in one file inside any function scope (main or anyother), this change doesn't get reflected to all this char array's future references from any other file later, but instead in each file((or maybe inside in each function) its content is preserved??
How to make such that, I can use a specific part of char array (memory region) which is GLOBALLY accessible from all "files" and in their functions, and all references get correct readings?
thnx
With your current approach you have two copies of the array. Instead you need to declare the array in temp.h (with extern instead of static) and define it elsewhere, for instance in in temp.c:
temp.h:
#ifndef TEMP_H
#define TEMP_H
extern char buffer[1000];
#endif
temp.c:
#include "temp.h"
char buffer[1000] = "ABC";
You can also probably find a more descriptive name than temp for the module. It is also a good idea to add a prefix to the buffer variable, e.g. temp_buffer so that you avoid potential name clashes and make it easier for yourself and others to find where the array is declared.
Ok...GOT IT!... now I solved!
In a singly included header file (( which is temp.h in question )) u must write:
extern char buffer[];
Note: single inclusion of this temp.h file can be achieved by "#ifndef-#endif" pairs in other ".c" and ".h" files of the compilation.
And next, include only in one of the files the following statement of definition:
char buffer[1000];
I hope this solution helps some guys.
I am attempting to define a set of global variables which will configure my device, about 10 in a dedicated .c file, that will be changed on a regular basis at compile time (as per device requirements), I want these to be in this separate file so they can all be changed easily. These variables are then called throughout my program in various files. And are never changed only read. The problem is that my compiler (XC8 for PIC MCU's) doesn't define the variable, as it can only see that one use of the variable in the file, even though it is called with extern throughout the program.
config.h
unsigned int Global_A;
unsigned int Global_B;
void config(void);
config.c
void config(void)
{
unsigned int Global_A=987;
unsigned int Global_B=123;
}
prog_a.h
extern unsigned int Global_A;
extern unsigned int Global_B;
unsigned int var_A;
void prog_a(void);
prog_a.c
unsigned int var_A=0;
void prog_a(void);
{
var_A=Global_A+Global_B;
}
main.c
#include config.h
#include prog_a.h
void main(void)
{
while(1)
{
config();
prog_a();
}
}
as a result, the equivalent var_A is always 0, as the compiler has done away with config.c as it cannot see the variable called again.
I'm assuming the answer is very obvious to those more versed, but I can't find anything online. I have not had any trouble with using extern and globals before when they are used in the file the are defined in. But I could just be using it wrong fundamentally, so feel free to berate me.
Thanks in advance.
p.s if it wasn't obvious this is an example code to illustrate my problem.
Your function config declares two new variables in the scope of the function (their names hide those of the global variables). They don't exist anywhere outside of it, and assigning a value to them does nothing. If your goal was for it to initialize the globals, you need do this:
// config.h
extern unsigned int Global_A;
extern unsigned int Global_B;
void config(void);
// config.c
unsigned int Global_A;
unsigned int Global_B;
void config(void) {
Global_A=987;
Global_B=123;
}
With extern keyword it it necessary to declare the variable once (preferably in a header file) define it once in a .c file that has visibility to the declaration statement. That is it. Where the extern defined variable is necessary, #include the header file in which the declaration statement occurred.
Also note it is important also to define extern variable(s) in global scope (i.e. not in a function).
config.h:
#include "prog_a.h"
//unsigned int Global_A;
//unsigned int Global_B;
void config(void);
main.c
#include config.h
#include prog_a.h
...
//suggest defining these here:
unsigned int Global_A=0;//define outside of function
unsigned int Global_B=0;
...
config.c
#include "prog_a.h"
...
void config(void)
{
Global_A=987;
Global_B=123;
}
Your global variables are all of type int, so why not just use #define?
Change file config.h to
#define Global_A 789
#define Global_B 123
You do not actually have to declare any int variables to hold those values, plus, they will be const and unmodifiable.
That's they way that we did it "back in the day", but in the last decade or two, I see more and more actually storing these configuration values in an external text file
It can be a .INI, or XML or JSON, etc, etc, that is up to you.
You just create different files, let's say Singapore.ini and Paris.ini and Auckland.ini, etc, each containing a key/value pair.
e.g
time_zone = X
population = Y
etc, etc
Then, at the start of your main, read the file in and store the values -but not in globals, which are frowned upon, these days. Read them into variables which are local to config.c, and have config.c/h provode methods to read their values, e.g GetTimeZone() and GetPoulation(), etc
Don't worry about any code size or run time impact of this, as any decent compiler will in-line these function calls.
One advantage to reading "global" configuration values in an external text file is that you only need to build your software once. You do not need to rebuild and have an executable for each configuration, which the road that you are currently heading down.
Firstly, this makes it easier to test your software (especially automated test), by merely editing the text file, or supplying a new one.
Also, since you only have a single executable, you can ship that to all of your users/customers, and give each a tailored config file. You can totally control & change the functionality of your software just by changing the config file. You might want to think about that.
Alongside main.c file, I have following my_custom_data_structure.c file in my project. My my_custom_data_structure.c file contains a lot of variables, functions, etc.
I am using #include "my_custom_data_structure.c" directive in main.c.
Problem
I would like to import only single function called foo from my_custom_data_structure.c. I don't need all the variables and functions, which are declared in my_custom_data_structure.c file.
Any insights appreciated.
File structure
-
|- main.c
|- my_custom_data_structure.c
Content of my_custom_data_structure.c
#include <stdio.h>
int DELAY = 20;
int SPEED = 7;
char GRANULARITY_CHAR = 'g';
unsigned int RANGE = 3;
void foo(){
// TODO: In future, this function will print SPEED.
printf("foo works!");
}
/*
The rest of this file is filled by a lot
of code, which is not needed for main.c
*/
Content of main.c
#include <stdio.h>
#include "my_custom_data_structure.c"
int DELAY = 3;
int main(){
foo();
printf("Delay is %d", DELAY);
return 0;
}
UPDATED: Added working example
The usual way is to compile them separately. So you have your main.c, and your extra.c, and you should create a extra.h (and include it in main.c).
In this extra.h, put in declarations for anything that is to be exported from your extra.c file.
For example any functions that should be available to other files. All other functions should be declared/defined only in your extra.c as static, so that they are not available as symbols to be linked when main.c is compiled.
Normally, you don't include source files (.c) inside other source files (or inside headers). It's possible (and occasionally necessary), but it isn't usual.
Unless you've designed the my_custom_data_structure.c to allow you to specify which functions are to be compiled, you get everything in the file. For example, you could use:
#ifdef USE_FUNCTION1
void function1(void *, …)
{
…
}
#endif /* USE_FUNCTION1 */
around each function, and then arrange to
#define USE_FUNCTION1
before including the source, but that's not usually a good way of working. It's fiddly. You have to know which functions you use, and which other functions those need, and so on, and it is vulnerable to changes making the lists of USE_FUNCTIONn defines inaccurate. Of course, the source code might have blocks of code like:
#ifdef USE_FUNCTION1
#define USE_FUNCTION37
#define USE_FUNCTION92
#define USE_FUNCTION102
#endif /* USE_FUNCTION1 */
so that if you say you use function1(), it automatically compiles the other functions that are required, but maintaining those lists of definitions is fiddly too, even when the definitions are USE_MEANINGFUL_NAME instead of a number.
Create a header (my_customer_data_structure.h) declaring the functions and any types needed, and split the implementation into many files (mcds_part1.c, mcds_part2.c, …).
Compile the separate implementation files into a library (e.g. libmcds.a), and then link your program with the library. If it's a static library, only those functions that are used, directly or indirectly, will be included in the executable.
To simplify my code, I make the code snippet below to explain my question:
def.h
#ifndef _DEF_H_
#define _DEF_H_
const char draw[] = "Draw on the canvas:"
#endif
circle.c
#include "def.h"
void draw_circle(void)
{
printf("%s %s", draw, "a circle.");
}
main.c
#include "def.h"
int main(void)
{
printf("%s %s", draw, "nothing.");
}
The problem is that there will be no problem at compile-time but it will probably fail on link-time because of the redefinition of const char array, draw[].
How to prevent this problem to share a const char array between two source files gracefully without putting them into a single compilation unit by adding #include"circle.c" at the top of main.c?
Is it possible?
You get multiple definition error when linking because, you put the definition of draw in a header file. Don't do that. Put only declarations in the header, and put definitions in one .c file.
In you example, put this in a .c file
const char draw[] = "Draw on the canvas:"
And put this in the header:
extern const char draw[];
Unfortunately there are no real named constants in C for such types. The only possibility are macros. For strings you could do
#define draw "Draw on the canvas:"
or if you want to insist that it is const qualified:
#define draw (char const*)"Draw on the canvas:"
#define draw (char const[]){ "Draw on the canvas:" }
The last shows the possibility for other types, use compound literals. Here using const is important, such that the compiler may optimize better.
I have such project, which includes 1.c 2.c and mygost.h files.
//mygost.h looks this way
#ifndef MYGOST_H_
#define MYGOST_H_
#include <stdint.h>
uint8_t transl_table(uint8_t in, uint8_t n) {
return tbl[n][in];
}
const char *get_filename_ext(const char *filename)
{
const char *dot = strrchr(filename, '.');
if(!dot || dot == filename) return "";
return dot + 1;
}
#endif
//1.c
#include <malloc.h>
#include "mygost.h"
// here we call defined before functions
//2.c
#include <malloc.h>
#include "mygost.h"
// here we call defined before functions
If I include this header only in one .c file, everything will be fine. Otherwise I get Multiple definition error of const char *get_filename_ext(const char *filename) function and all other function in the header. In addition, I dont redefine these functions in a code at all. Don`t know how to fix this.
I use QNX Momentics Tool Suite, which has own compliler (http://www.qnx.com/products/tools/qnx-momentics.html), but it works like gcc as far as I know.
UPD1: Compiler gives such errors
Severity and Description Path Resource Location
2.c: multiple definition of `get_filename_ext' GostQnx line 0
..........
make[2]:***[C:/ide-4.5-workspace/GostQnx/x86/o-g/GostQnx_g] Error1 GostQnx line 0
make[2]:***[C:/ide-4.5-workspace/GostQnx/x86/o/GostQnx] Error1 GostQnx line 0
first defined here GostQnx mygost.h line 16
................
multiple definition of `get_filename_ext'GostQnx mygost.h line 151
..........
UPD2: adding static or inline don`t effect.
You should not define a function in a .h file. The error is most likely the missing function prototype const char *get_filename_ext(const char *);
(edited following comment)
//mygost.h looks this way
#ifndef MYGOST_H_
#define MYGOST_H_
#include <stdint.h>
extern uint8_t transl_table(uint8_t in, uint8_t n);
extern const char *get_filename_ext(const char *filename);
#endif
//mygost.c looks this way
#include "mygost.h"
extern uint8_t transl_table(uint8_t in, uint8_t n) {
return tbl[n][in];
}
extern const char *get_filename_ext(const char *filename)
{
const char *dot = strrchr(filename, '.');
if(!dot || dot == filename) return "";
return dot + 1;
}
When you include in 1.c, the compiler declares the function and make an assumption on it's prototype since it is not defined. And does the same the second time it is included in 2.c. The usual way would be to declare a function prototype in mygosh.h, and put the actual function declaration in a mygosh.c containing the implementation details.
Bear in mind that I only rewrote according to your example (for example I did not correct the undeclared variable in trans1_table)
Having the full output from the compiler would help to be more precise. As the compiler and platform (ex: gcc 4.7 under ubuntu 12.04).
Also, I tried to compile your code under fedora 19 with gcc 4.7 and it does not compile because of some unknown types that are either defined elsewhere in your real project or because it could also be a cause of your problem. Try to rewrite as a self contained compilable example. If you want, you can check a gitorious project I started out a while ago for another stack overflow question you can look at for ideas.
https://gitorious.org/c-cli-rubix-cube