Why this code below fails - c

#include <stdio.h>
int *top;
int a=1;
top=&a;
void main()
{
printf("%d\n",*top);
}
error C2440: 'initializing' : cannot convert from 'int *' to 'int'
UPDATE
I know how to make it work,but I'm asking why it DOESN'T work.

You're actually tripping over the compiler's support for ancient C syntax. The original C compiler allowed declarations without a type, defaulting it to int. So outside of any function,
foo;
would declare a global int variable called foo. So when you say
top = &a;
it declares a global int variable called top and tries to initialize it with the address of a. This gives you the two errors you see -- two conflicting declarations for top and an inability to convert an int * to an int. Of course those same ancient C compilers would not give you the second error, happily converting the address to an int without complaint.
This also tells you why int i; i = 100; works --- its two declarations for i as a global int variable (which is ok, as they're the same type), and the second initializes it to 100 (which is ok as only one declaration has an initializer)
There's lots of fascinating stuff in Dennis Ritchie's The Development of the C Language

I'm a bit surprised at the exact error message you got about it, but the problem (or at least one of the obvious problems) is that outside of a function, you're allowed to define and initialize variables, but you're not allowed to do a normal assignment -- that has to be done as part of executing a function. As such, your top=&a; isn't allowed.
Another problem is that you have main returning void, where it should return an int (though most compilers will accept that without even a warning, not to mention an error message).

Actually, from your original code:
int *top;
int a=1;
top=&a;
As others have mentioned - in global space you can declare, or declare and initialize. You can not do assignment.
What is actually happening in the line top = &a; is that you are actually re-declaring a variable called top, and it defaults to the int type. The compiler should actually warn about creating a new variable named top that has the same name as a previously declared variable, as well as generate an additional warning that you are creating a variable of default type int.
In C, variables that are declared without a type default to int, and that would generate the error you see.
error C2440: 'initializing' : cannot convert from 'int *' to 'int'
What this is really complaining about is that top = &a; as in your code actually looks like int top = &a; to the compiler, so you are trying to bind an int* to int.

This works:
#include <stdio.h>
int *top;
int a=1;
int main()
{
top=&a;
printf("%d\n",*top);
}
You need to be sure not do global assignment like that. You can only do initialization, nothing else for global variables.
You also have not mentioned the other errors, please mention all errors, sometimes one error is based of another and when one is fixed the others get fixed. In this case it was:
Conflicting types for 'top'.

Another option:
#include <stdio.h>
int a=1;
int *top=&a;
void main()
{
printf("%d\n",*top);
}

I honestly have no idea why that fails, but this works:
#include <stdio.h>
int a = 1;
int* top = &a;
void main()
{
printf("%d\n", *top);
}
And remember: ALWAYS INITIALIZE YOUR POINTERS!!
If you're not going to assign them immediately, at least do something like this:
int* top = 0;

Related

Clang-Tidy: Initializing non-local variable with non-const expression depending on uninitialized non-local variable, C pointer reference

We have a very simple bit of code which is giving a warning but seems like it should be fine, and runs fine. We understand that in general there may be issues with order of initialisation between compilation units, but in this case we are initialising with a pointer, so don't understand how order can cause a problem, or how any problems might arise with this code. Note that in the real code we have more complex scenario with structs, but code below shows the basic issue.
EDIT: have removed const qualifiers as they don't affect the warning
file1.c
int foo=42;
file2.c
#include <stdio.h>
extern int foo;
// Clang-Tidy: Initializing non-local variable with non-const expression depending on uninitialized non-local variable 'foo'
int *bar=&foo;
int main() {
printf("%d\n", *bar); // prints '42'
}
Warning is not from gcc but from clang-tidy. To reproduce run:
clang-tidy -checks=* file1.c file2.c
clang-tidy is warning about something that just is not a problem: whether foo is initialized or not does not make a difference in this initializer where only its address is taken.
Furthermore foo is a global variable, hence it is either statically initialized in the module that defines it or it does not have an initializer and is initialized to 0 by the loader at run time. If the program was compiled as C++, foo might be initialized at runtime, before main is called, potentially by running initializer code, but again this does not make a difference as only its address is used in int *bar = &foo;
You should just disable this warning, as explained by Cameron Tacklind.
As others have mentioned, clang-tidy is telling you precisely what is wrong.
In this case, I think the clincher is the first part of the sentence: "Initializing non-local variable ...".
The particular warning will go away if bar is declared (and defined) inside main():
#include <stdio.h>
extern int foo;
int main() {
int *bar=&foo; // Still warns about const issues
printf("%d\n", *bar);
}
Alternatively, you can ignore the specific rule for those specific lines pretty easily:
#include <stdio.h>
extern int foo;
// NOLINTNEXTLINE(cppcoreguidelines-interfaces-global-init)
int *bar=&foo;
int main() {
printf("%d\n", *bar);
}

Variable declaration not properly checked by compiler

When declaring a variable or pointer, the compiler assumes the variable or pointer itself is already declared when being assigned as a value during declaration.
I have tried both gcc and clang and they compile the "faulty" code without complaining.
CASE 1: This will not compile since "a" is not declared:
void main()
{
int b=sizeof(a);
}
CASE 2: This compiles without a problem:
void main()
{
int a=sizeof(a);
}
Shouldn't the compiler generate the "a is undeclared" error instead, just like in case 1?
Shouldn't the compiler generate the "a is undeclared" error instead, just like in case 1?
Why? It just saw you declare a.
int a = sizeof(a);
// ^--- here it is, before its first use
The declaration of a variable begins after its declarator is seen, right before its (optional) initializer. So you can even write the truly faulty
int a = a;
Note however that in your case there is nothing faulty being done. The result of sizeof depends only on the type of a, and the type is known. This is a well defined initializtion (with a conversion from size_t to int, but not one to be worried about).
sizeof is not a function depending on the value of a; it is a builtin that is evaluated at compile time, so it becomes equivalent to
int a = 4;

struct X declared inside parameter list will not be visible outside of this definition or declaration [duplicate]

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.

What do I get if I declare an array without a size in global scope?

In one of the answers in Tips for golfing in C, I saw this code (ungolfed version):
s[],t;
main(c){
for(scanf("%*d "); ~(c=getchar()); s[t++]=c)
putchar(s[t]);
}
I think that the above program exhibits UB (but who cares in code golf?). But the thing that I don't understand is the s[] in global scope. I know that when the type of a global variable isn't specified, it defaults to int. I created a small program which surprisingly compiles:
#include <stdio.h>
int s[];
int main(void)
{
printf("Hello!");
}
though it emits one warning:
prog.c:23:5: warning: array 's' assumed to have one element [enabled by default]
int s[];
^
What is s in the above program? Is it an int* or something else?
Will this be useful anywhere?
What is s in the above program? Is it an int* or something else?
s is an incomplete type. That's why you cannot sizeof it. As #BLUEPIXY suggests, it's initialized with zero because it's declared in global scope making a "tentative definition".
int i[];
the array i still has incomplete type, the implicit initializer causes it to have one element, which is set to
zero on program startup.
Now,
Will this be useful anywhere?
It's pretty useless if you're just using s[0] because at that point you go for s; directly. But, if you need an array with a certain size and you don't care about UBs, it's "okay".

Do functions in C need to have types?

The Problem
I'm writing the following code, which, as excerpted below, should return the total amount of money depending on the number of each type of coin.
static int qNum = 0;
static int dNum = 0;
static int nNum = 0;
static int pNum = 0;
int main(){
float totalCost;
totalCost = totalMoneyCalc();
}
float totalMoneyCalc(void){
float total;
total = qNum*.25 + dNum*.10 + nNum*.05 + pNum*.01;
return total;
}
The Errors I'm Getting
note: previous implicit declaration of ‘totalMoneyCalc’ was here
totalCost = totalMoneyCalc();
error: conflicting types for ‘totalMoneyCalc’
float totalMoneyCalc(){
However, when I remove the "float" part of the totalMoneyCalc() function, it doesn't return any more errors. Aren't you supposed to assign functions types?
What I've Tried
I looked at this question on SO, which says something about having to pass in void as a param for functions that don't take in anything but adding that to the original code didn't work either.
I also checked out some primers on using floats for functions in C, but I followed those and it's still not working.
Am I supposed to be doing something with pointers? I don't understand why returning a value in a function to be assigned to a variable is different from ints to floats. If anyone has suggestions, fixes, or explanations, I'd really appreciate it.
Yes, all C functions have types. Prior to the 1999 standard, it was legal to omit the return type from a declaration; that would implicitly give it a return type of int. As of C99, the return type must always be specified explicitly.
Also prior to C99, it was legal to call a function with no visible declaration. The compiler would assume a function with a return type of int (that's the "previous implicit declaration" referred to in the error message). C99 dropped that rule; now all functions must be visibly declared before you can call them.
Assuming you're using gcc (that looks like a gcc error message), the compiler enforces the C90 rules by default. The problem it's reporting is that the implicit declaration of totalMoneyCalc (as a function returning int) conflicts with the later explicit declaration as a function returning float.
The solution is to declare totalMoneyCalc before the call. You can either add a separate "forward" declaration before main:
float totalMoneyCalc(void);
or you can move the entire definition above main. (This is a good idea even in C90.)
A minor point: int main() should be int main(void).
The compiler needs to know about the function before you use it. If the function is unknown to the compiler then it will not be able to know whether the function returns double or float or if it's first parameter is a pointer or a struct, so it will by default think of them all as int's.
You can to add a function prototype before main()
float totalMoneyCalc(void);
or move the entire function definition before main().

Resources