I wrote the following code:
struct DVDARRAY
{
int length;
pDVD* dvds;
};
typedef struct DVDARRAY DVDARRAY_t;
//...
int main()
{
int i;
char c;
DVDARRAY_t* dvds;
poDAOproperties props;
props = get_dao_properties();
dvds = (DVDARRAY_t*) DVDDAO_read_raw_filter(props, "id = 1");
printf("title->: %s", dvds->dvds[0]->title);
}
and in another file the following is defined:
DVDARRAY_t* DVDDAO_read_raw_filter(poDAOproperties properties, char* filter)
{
DVDARRAY_t *dvds;
// ...some code...
dvds = malloc(sizeof(DVDARRAY_t));
// ...some code...
return dvds;
}
Now my question: when I try to compile these files I get the following warning:
src/main.c: In Funktion »main«:
src/main.c:80:9: warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Line 80 of main.c is exactly that line:
dvds = (DVDARRAY_t*) DVDDAO_read_raw_filter(props, "id = 1");
What can I do?
You do not list the file names above so I will just call them main.c and dvd.c.
In main.c, you make a call to the otherwise undeclared function DVDDAO_read_raw_filter. This tells the compiler to assume that the function exists, has an unknown (but fixed) set of arguments, and has a return value of type int.
In dvd.c you define the function DVDDAO_read_raw_filter with fixed (and known) arguments, returning type DVDARRAY_t*. (Presumably you have to repeat the definition of DVDARRAY_t first.)
Note that main.c believes something untrue about DVDDAO_read_raw_filter, namely, that it has return type int. This is causing your compile-time diagnostic. By luck (you can decide for yourself whether this is good or bad luck :-) ) the program runs successfully in spite of this incorrect belief.
To fix the problem, tell main.c about the function before calling it, i.e., declare it. You can also get a more explicit warning from gcc by adding -Wimplicit-function-declaration to your compile-time flags.
In general, it's a good idea to put struct definitions, typedefs, and function declarations into a header file (e.g., dvd.h) and then #include that header in the various C source files that make use of the definitions and declarations. That way the compiler can compare the function declarations against the function definitions, and you need not repeat the contents of structs and the names of typedefs in multiple .c files.
If you are just trying to make things work...
unsigned char *temp;
int number;
temp = someArr[y][x].charAtThisLoc;
number = (int)(size_t)temp;
other solutions didn't work for me.
Related
I just found a quirk in C that I find really confusing. In C it's possible to use a pointer to a struct before it has been declared. This is a very useful feature that makes sense because the declaration is irrelevant when you're just dealing with a pointer to it. I just found one corner case where this is (surprisingly) not true, though, and I can't really explain why. To me it looks like a mistake in the language design.
Take this code:
#include <stdio.h>
#include <stdlib.h>
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
Gives:
foo.c:6:26: warning: ‘struct lol’ declared inside parameter list [enabled by default]
foo.c:6:26: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
foo.c:8:16: warning: ‘struct lol’ declared inside parameter list [enabled by default]
To remove this problem we can simply do this:
#include <stdio.h>
#include <stdlib.h>
struct lol* wut;
typedef void (*a)(struct lol* etc);
void a2(struct lol* etc) {
}
int main(void) {
return 0;
}
The unexplainable problem is now gone for an unexplainable reason. Why?
Note that this question is about the behavior of language C (or possible the compiler behavior of gcc and clang) and not the specific example I pasted.
EDIT:
I won't accept "the order of declaration is important" as an answer unless you also explain why C would warn about using a struct pointer for the first time in a function argument list but allow it in any other context. Why would that possibly be a problem?
To understand why the compiler complains, you need to know two things about C "struct"s:
they are created (as a declared, but not yet defined, type) as soon as you name them, so the very first occurrence of struct lol creates a declaration
they obey the same "declaration scope" rules as ordinary variables
(struct lol { declares and then begins defining the structure, it's struct lol; or struct lol * or something else that does not have the open-brace that stops after the "declare" step.)
A struct type that is declared but not yet defined is an instance of what C calls an "incomplete type". You are allowed to use pointers to incomplete types, as long as you do not attempt to follow the pointer:
struct lol *global_p;
void f(void) {
use0(global_p); /* this is OK */
use1(*global_p); /* this is an error */
use2(global_p->field); /* and so is this */
}
You have to complete the type in order to "follow the pointer", in other words.
In any case, though, consider function declarations with ordinary int parameters:
int imin2(int a, int b); /* returns a or b, whichever is smaller */
int isum2(int a, int b); /* returns a + b */
Variables named a and b here are declared inside the parentheses, but those declarations need to get out of the way so that the the next function declaration does not complain about them being re-declared.
The same thing happens with struct tag-names:
void gronk(struct sttag *p);
The struct sttag declares a structure, and then the declaration is swept away, just like the ones for a and b. But that creates a big problem: the tag is gone and now you can't name the structure type ever again! If you write:
struct sttag { int field1; char *field2; };
that defines a new and different struct sttag, just like:
void somefunc(int x) { int y; ... }
int x, y;
defines a new and different x and y at the file-level scope, different from the ones in somefunc.
Fortunately, if you declare (or even define) the struct before you write the function declaration, the prototype-level declaration "refers back" to the outer-scope declaration:
struct sttag;
void gronk(struct sttag *p);
Now both struct sttags are "the same" struct sttag, so when you complete struct sttag later, you're completing the one inside the prototype for gronk too.
Re the question edit: it would certainly have been possible to define the action of struct, union, and enum tags differently, making them "bubble out" of prototypes to their enclosing scopes. That would make the issue go away. But it wasn't defined that way. Since it was the ANSI C89 committee that invented (or stole, really, from then-C++) prototypes, you can blame it on them. :-)
The compiler is warning you about a forward declaration of struct lol. C allows you to do this:
struct lol; /* forward declaration, the size and members of
struct lol are unknown */
This is most used when defining self-referencing structs, but it is also useful when defining private structs that are never defined in the header. Because of this latter use case, it is allowed to declare functions that receive or return pointers to incomplete structs:
void foo(struct lol *x);
However, just using an undeclared struct in a function declaration, as you did, will be interpreted as a local incomplete declaration of struct lol whose scope is constrainted to the function. This interpretation is mandated by the C standard, but it is not useful (there is no way to construct the struct lol to pass to the function) and is almost certainly not what the programmer intended, so the compiler warns.
This is because, in the first example, the struct is previously undefined and so the compiler tries to treat this first reference to that struct as a definition.
In general, C is a language where the order of your declarations matters. Everything you use should be properly declared in advance in some capacity, so that the compiler can reason about it when it's referenced in other context.
This is not a bug or a mistake in the design of the language. Rather, it's a choice that I believe was made to simplify the implementations of the first C compilers. Forward declarations allow a compiler to translate the source code serially in one pass (as long as some information such as sizes and offsets is known). If this weren't the case, the compiler would have be able to go back and forth in the program whenever it meets an unrecognized identifier, requiring its code emission loop to be much more complex.
I see this same warning before. My fix is to include the proper header file which contains the definition of the struct.
In addition to other answers, I would like to post a code example, which makes the problem more obvious. Please consider the following:
int testFunc(struct SomeStruct {int a; int b;} param1) // gcc: warning ...
{
return param1.a + param1.b;
}
int main(void)
{
struct SomeStruct params; // gcc: error: storage size of 'params' isn't known
params.a = 25;
params.b = 15;
return testFunc(params);
}
As you can see, the function declaration of testFunc is considered a valid C code (tested with GCC 12, Clang 15 and MSVC 19.32). However, you can't really use it because SomeStruct is only valid within the scope of the function, which is what compiler warns you about.
I've stumbled on this myself when working on my own C parser as the allowance of such syntax makes parser development easier as you can reuse the same implementation to parse struct declaration inside function parameter lists. It is surprising, however, that such bizarre syntax is still considered valid nowadays (as of C17) and instead of error you just get a warning.
Lookout for typos and DOUBLE CHECK your line numbers! I concat all my source files before compiling, so the line numbers from the source I am working in are meaningless. I have to take extra time to open up the concatted payload and examine it. So usually I don't and I just assume I know what line I am looking at from the console output message.
Example:
GCC Says:
EXAMPLE.C11:27:1: error: 'struct THIS_STRUCT_IS_OK' declared inside
parameter list [-Werror] ){
#include <stdio.h> //:for: printf(...)
struct THIS_STRUCT_IS_OKAY{
int whatever;
};
int LookingAtThisFunction(
struct THIS_STRUCT_IS_OKAY* arg
){
//: (Because you are not checking line numbers, you )
//: (assume you are looking here. But you are not. )
//: (Maybe you are concatenating all of your source )
//: (files together before compiling and line numbers )
//: (don't correspond to the original source and you )
//: (didn't examine your concatted source code payload?)
return( arg -> whatever );
}
//:You are not looking here because this is later in the
//:file, so the compiler would be complaining about the
//:FIRST usage of the struct, not the second one, you assume.
//:And you would be correct, if there wasn't a typo.
void WhereYouAreNotLooking(
struct THIS_STRUCT_IS_OK* arg
){
LookingAtThisFunction( arg );
}
int main( void ){
}
In summary: If you know what the error message means. And you swear to god
the compiler is broken because you already checked that...
1. Look for typos.
2. Make sure you are really looking at the correct line number.
I get that this is kinda stupid. But it had been scratching my head for
half an hour. So hopefully it helps someone who's already looked at the
obvious solutions.
I want to assign a particular value to a (user defined) global variable in C programming language. When I am doing this from within any other function or main it is fine. But when I am doing it from global space (outside of any function) it is giving the following compilation error:
[expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘.’ token]
Following is a code snippet which causing issue:
#include <stdio.h>
#define MAX_SIZE 5
typedef struct
{
int val[MAX_SIZE];
int top;
}stack_t;
stack_t s;
s.top = -1; // <== Initialization from here is causing compilation error
main()
{
//s.top = -1; < === Initialization from here is fine
printf("s.top =%d\n", s.top);
return 0;
}
But same kind of assignment for integer variables is not giving only warning
#include <stdio.h>
int i,j,k,l;
k=10;
main()
{
printf("i= %d, j=%d k=%d l=%d\n", i, j, k, l);
return 0;
}
Can anyone please tell the reason for this?
The error from the assignment of s.top is not surprising. It is not an initialization but an assignment, and those are different concepts in C. You can't have assignments outside of functions.
The interesting part here is that it looks like you can do an assignment of the integer variable k. But that is an illusion, since in that case it's not an assignment but an initialization!
The line
k = 10;
is interpreted not as an assignment but as a variable definition. A hint to this is that GCC gives the warnings "data definition has no type or storage class" and "type defaults to 'int' in declaration of 'k'". So the line could be written as
int k = 10;
As Matt wrote in a comment below, leaving out the data type like this seems to be a GCC extension, and not something that the standard allows.
(By the way, do turn on warnings in your compiler, and pay attention to them!)
But wait, wasn't there already a definition of k on the line above, and you can't have more than one definition, can you?
First, remember that C makes a distinction between definitions and declarations. A definition of a variable is when you "create" the variable, and optionally give it an initial value. A declaration is when you just tell the compiler that the variable exists, and its name and data type, but the definition is elsewhere. You can have both a definition and one or more declarations of the same variable. For example:
int xxx = 10; // This is the definition of xxx
int xxx; // This is a declaration of xxx
int xxx; // Another delaration of xxx
But sometimes the compiler can't determine if what it sees is a declaration or a definition, and then it is interpreted as a "tentative definition", or in other words "perhaps a definition, perhaps just a declaration, we'll decide later". For example:
int yyy;
Is that a definition of the variable yyy (without an initial value), or is it just a declaration, where the definition will be found elsewhere? The compiler doesn't know, so it waits to decide, and calls this a tentative definition.
When the compiler sees your first declaration of k (along with the other variables i, j and l) it is interpreted as a tentative definition, and when the later definition is found, that tentative definition of k will be decided to be a declaration, not a definition.
C code has to be inside a function. You can declare a global outside of a function but you can't write an assignment statement outside of a function. That is you can set the initial value as part of declaring the struct but you can't then change it. Here your declaration is only the "stack_t s;" line.
Everything in C ends up compiling to symbols in a binary format (an example would be the ELF format). Symbols have names, so functions are named chunks of code, and globals are named chunks of data. There are no "free floating" chunks in the compiled binary, everything has to go under a name.
In the C model, code floating around outside of a function doesn't make sense because C doesn't have a place where it would run that code. C never runs a file in the way that bash or Python or javascript does; it only runs binaries. So it only runs named
functions. The files are only known at compile time not runtime.
Initializing the outside the main is reason for that error. You can do that using like this.
stack_t s={.top=-1};
It will allow you to do the initialization while declaring. Refer this link. or this It can be useful.
There are differences between assignment and initialization. You should note that, assignment can't be done outside of a function. The statement
s.top = -1;
is an assignment not an initialization.
C99 and latter provides designated initialization of structs and arrays. So, you can initialize only the top member of struct s as
stack_t s = { .top = -1 };
and other members will be initialized to 0 by the compiler.
In the global space you can only initialize and declare the variables but cannot assign the value to variables. In your code you are assigning the value to member of struct so its throwing error and same holds true for integers for your below code.
Try the below code in the global space and it works fine:
typedef struct
{
int val[MAX_SIZE];
int top;
}stack_t;
stack_t s={{},-1};
main()
{
printf("s.top=%d",s.top);
return 0;
}
Background
I'm using the C interface to the GMP library and I have a need to manipulate arrays of integers. Main type for integers in the GMP library is mpz_t, and GMP is using a trick to allow the users to use gmp_z without explicit allocation, while being able to pass them around as pointers. Namely the gmp_z type is defined as follows.
typedef struct
{
int _mp_alloc;
int _mp_size;
mp_limb_t *_mp_d;
} __mpz_struct;
typedef __mpz_struct mpz_t[1];
This is neat, but I am having trouble passing arrays of mpz_t to functions that operate on const arrays.
Example
To exemplify consider this simple non-GMP program.
#include <stdio.h>
typedef struct {
int x;
} x_struct;
typedef x_struct x_t[1];
void init_x(x_t x) {
x->x = 23;
}
void print_x(const x_t x) {
printf("x = %d\n", x->x);
}
// I'm just printing so taking a const array
void print_x_array(const x_t* x_array, size_t n) {
size_t i;
for (i = 0; i < n; ++ i) {
printf("x[%zu] = %d\n", i, x_array[i]->x);
}
}
int main() {
x_t x; // I can declare x and it's allocated on the stack
init_x(x);
print_x(x); // Since x is an array, pointer is passed
x_t x_array[3];
init_x(x_array[0]);
init_x(x_array[1]);
init_x(x_array[2]);
print_x_array(x_array, 3); // Compile warning
}
The program uses the GMP trick, just showing off the usage. Compiling this program gives an annoying warning
gcc test.c -o test
test.c: In function ‘main’:
test.c:33:3: warning: passing argument 1 of ‘print_x_array’ from incompatible pointer type [enabled by default]
test.c:17:6: note: expected ‘const struct x_struct (*)[1]’ but argument is of type ‘struct x_struct (*)[1]’
Question
Since I'm not a C expert, can someone please shed more light on why this warning is happening at all. More importantly, is there a way to get around this warning while still using mpz_t (or x_t in the example)?
Just cast it to const:
print_x_array((const x_t *)x_array, 3); // Should be ok
First, let's note that the compiler warning you are getting has absolutely nothing to do with GMP, their strategy of typedefing a mpz_t type as an array of size one so that it facilitates some function calls within the library (but only facilitates scalar argument passing), nor to the passing of arrays to functions, and nor its a real problem in itself actually.
The problem all relies on the const declaration of function parameter input, and that is not a true issue. Its good to have that definition, so compiler will balk if function writer attempts to modify the object being passed to the function. But burden cannot be put on function callers!
In my setting (OpenSUSE, x86_64, gcc version 9.2.1) your code does not gives a warning and works perfectly fine if I don't use the -pedantic compiler option. This is because, as Michael Pankov stated, the (old) C standard is pretty tight and sometimes cumbersome, while compilers today are very smart. The compiler does now what you want, and will provide you correct code, be assured of that. Also, in your environment it seems there will be many more people calling the function than changing it, so it can be quite assured the input will not be unduely modified, and you can ignore the warning altogether.
For ignoring this specific warning check here for GCC, other compilers also provide this options.
About the const on function parameter input check here, I particularly like this answer: "If your code has many people working on it and your functions are non-trivial then you should mark const any and everything that you can. When writing industrial-strength code, you should always assume that your coworkers are psychopaths trying to get you any way they can (especially since it's often yourself in the future).".
I have read this exam code.
"a.c":
int global_1 = 100;
"b.c":
extern int global_1;
int global_2 = global_1 * 2;
int main()
{
return 0;
}
gcc give “error: initializer element is not constant"
I do not write this code, but I want to know why and how to fix.
Thanks.
The problem you are facing is that in order to initialise a variable (global_2 here) it's value (or all values of what it depends on, in your case global_1) need to be known.
When you initialise a variable in a function then it's value only needs to be known at runtime and that is generally the case or you will get an undefined symbol error during compile or link time.
Globals need to be initialised by the compiler during compile time.
extern int global_1;
Says to the compiler that global_1 exists, but not in this compilation unit. It will be accessible after linking. You can use it in functions, but the linker needs to link it first with an object file that actually contains it.
Thus the compiler is unable to initialise it at compile time resulting in the error you see. Linking comes after compiling.
If you need to initialise globals that reference globals in a different compilation unit then you will need to do this in a function. For example the first stem in main().
The error says it all: Initialisers need to be constants.
To fix this you might like to modify your code like this:
int global_2 = 0;
int main()
{
global_2 = global_1 * 2;
I'm doing cast from a pointer then it keeps me runing this warning (assignment makes pointer from integer without a cast).
here's the code:
#include<stdio.h>
#include<stdbool.h>
typedef int TipoChave;
typedef struct TipoRegistro {
TipoChave Chave;
/*outros componentes*/
} TipoRegistro;
typedef struct TipoPagina* TipoApontador;
typedef struct TipoPagina {
int registros;
TipoRegistro *r;
TipoApontador *p;
} TipoPagina;
TipoApontador NovaSubArvore(int ordem){
TipoApontador A;
A=malloc(sizeof(TipoPagina));
int i;
A->registros=0;
A->r=malloc((2*ordem)*sizeof(TipoRegistro));
A->p=malloc((2*ordem+1)*sizeof(TipoPagina));
for (i=0;i<(2*ordem+1);i++){
A->p[i]=NULL;
if(i!=2*ordem){
A->r[i].Chave=0;
}
}
return (A);
}
on main I call:
TipoApontador Raiz;
then:
Raiz=NovaSubArvore(ordem); //Warning happens here
if I do:
if (Raiz!=NULL)
free(Raiz);
it runs a invallid free (strange, because if Raiz is NULL the free shouldn't had run.
Can anyone help me with that problem, please? I think that this warning is the problem that keeps me from "freeing" too.
EDIT: OK problem about waring solved. But if I do the free 2 times it runs a invalid free (I have a function that does a free somethings, other-times not. If I do the free the "if(Raiz!=NULL)" should block the other free from runing. but it isn't.
One problem is the calls to malloc() and the fact that you've not declared malloc() by including <stdlib.h>.
By default, functions are assumed to return an int in pre-C99 code — in C99 code, you're supposed to declare a function before using it.
You need to compile with more warning options. If you use GCC, I recommend:
gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes \
-Wold-style-definition ...
This pretty much ensures that you don't have undeclared functions (such as malloc()) used. Depending on the version of GCC you use, you may get more or less warnings enabled by default. In general, newer versions are fussier, though it isn't quite that simple.
The other problem appears to be that you have a source file (name not given in the question) containing type definitions and function definitions such as:
typedef struct TipoPagina* TipoApontador;
typedef struct TipoPagina { ... } TipoPagina;
TipoApontador NovaSubArvore(int ordem) { ... }
Within this file the types are known. In your main code, you have:
TipoApontador Raiz;
...
Raiz = NovaSubArvore(ordem); //Warning happens here
The type name TipoApontador must be known in this file, but it appears that your code does not include a declaration for NovaSubArvore().
For types and functions that are going to be used in multiple source files, there should be a header defining the types and declaring the functions. The header should be used in both the source file that defines the functions and in the source files that use the types and functions.
For example, the header might be tipopagina.h:
#ifndef TIPOPAGINA_H_INCLUDED
#define TIPOPAGINA_H_INCLUDED
typedef int TipoChave;
typedef struct TipoRegistro {
TipoChave Chave;
/*outros componentes*/
} TipoRegistro;
typedef struct TipoPagina* TipoApontador;
typedef struct TipoPagina {
int registros;
TipoRegistro *r;
TipoApontador *p;
} TipoPagina;
extern TipoApontador NovaSubArvore(int ordem);
#endif /* TIPOPAGINA_H_INCLUDED */
The header guards are important; they avoid problems with redefining types (though C11 has more flexibility than either C99 or C89 in handling redefinitions of typedefs). The use of extern before the function name is not strictly necessary, though I prefer to see it — if only for symmetry with the extern that must be present before any variables that are declared in the header (if there are any — global variables should be avoided whenever possible).
Then the implementation file tipopagina.c might start:
#include "tipopagina.h"
#include <stdlib.h>
TipoApontador NovaSubArvore(int ordem)
{
TipoApontador A = malloc(sizeof(TipoPagina));
...
return (A);
}
There's a good reason for putting the tipopagina.h header first; it ensures that the header can be used on its own (which is important).
The main code also includes tipopagina.h, and because the function NovaSubArvore() is declared in the header, you avoid the compiler warning.
The code looks okay but if I put main before NovaSubArvore is defined then I see the exact same error:
int main()
{
TipoApontador Raiz;
int ordem = 10 ;
Raiz=NovaSubArvore(ordem);
}
TipoApontador NovaSubArvore(int ordem){
/// Rest of the function
}
so in this case the return type will default to int. In K&R C i f you leave off the type it will default to int.
That looks OK to me. Are you sure the given definitions of TipoApontador and NovaSubArvore are the ones being referenced in main? Ways you might not be using those defintions are (for example):
Including a different header file than the one you've pasted from (if those live in a .h file)
Including another header file that also defines a type or function with that name, although I would expect a warning in this case
TipoApontadore or NovaSubArvore are actually undeclared in main, and the compiler is assigning default types. (This seems the most likely to me. If this is the case, you should expect a warning to this effect.)
Of course, this is not an exhaustive list, but those things have happened to me before.
EDIT: Also, are you turning on all warnings from the compiler? For example, if you're using gcc, are you using the -Wall option?
ok.... I think that it can't be done something like that:
free (Raiz)
if (Raiz!=NULL)
free(Raiz);
This will get invalid free anyway.
The rest of the problem it's solved by some answers there. I've accepted the most complete. But thanks everyone for trying to help!