This question already has answers here:
Does this self-assignment do something sensible?
(4 answers)
Compiler not detecting obviously uninitialized variable
(4 answers)
Closed 5 years ago.
While debugging a program of mine, I stumbled upon a weird behaviour of the gcc compiler. I don't know what's the correct title to describe this, but take a look at the code below.
Basically, I had a function which received a void* arg as an argument. It then casted it to a pointer of another type, HTTPRequest*. However, I casted the wrong variable, so the code looked like
void someCallback(void* arg) {
HTTPRequest* req = (HTTPRequest*) req;
FreeRequest(req);
//re-setup request, other stuff..
}
The program then crashed within FreeRequest with a SIGSEGV when it tried to derefrence the pointer. Upon further inspection, req always a had a value of NULL.
It took me a while to realize that the cast I did was just done on the wrong variabe - it should have been
HTTPRequest* req = (HTTPRequest*) arg;
Then it all worked. I was however baffled that gcc allowed me to not only compile this code, but throw no warning whatsoever at this line.
Consider the minimal example
#include <stdlib.h>
#include <stdio.h>
void someFunc(void* arg) {
int* a = (int*) a;
printf("a = %p\n", a);
printf("*a = %d\n", *a);
}
int main() {
int b = 42;
someFunc(&b);
return 0;
}
Compiled with
gcc -Wall -Wextra -Wpedantic -o test -O0 test.c && test.exe
Compiler outputs
test.c: In function 'someFunc':
test.c:7:9: warning: format '%p' expects argument of type 'void *', but argument 2 has type 'int *' [-Wformat=]
printf("a = %p\n", a);
^
test.c:4:21: warning: unused parameter 'arg' [-Wunused-parameter]
void someFunc(void* arg) {
^
And the program outputs:
a = 0061FFCC
*a = 6422500
With optimization at atleast O1 it outputs however:
gcc -Wall -Wextra -pedantic -o test -O1 test.c && test.exe
test.c: In function 'someFunc':
test.c:7:9: warning: format '%p' expects argument of type 'void *', but argument 2 has type 'int *' [-Wformat=]
printf("a = %p\n", a);
^
test.c:4:21: warning: unused parameter 'arg' [-Wunused-parameter]
void someFunc(void* arg) {
^
And outputs
a = 00000000
Then hangs.
So the question is: Why does gcc allow the compilation of expressions of the above form? This is obviously undefined behaviour. Then why are there no warnings about this, even with all warnings enabled?
Why does gcc allow the compilation of expressions of the above form? This is obviously undefined behaviour.
Because the standard allow this. Undefined behavior allow compiler to optimize code write in C. You can read this excellent article from llvm developer.
Then why are there no warnings about this, even with all warnings enabled?
-Wall -Wextra don't active all warning in gcc. clang has -Weverything but, gcc don't have such option.
Compiler are not force to print a warning message for everything. There are few warning that a compiler must print if it want to be standard compliant.
What you do is undefined behavior and this is not mandatory in the standard to print a warning.
clang 4.0.0 has a warning for this -Wuninitialized:
warning: variable 'a' is uninitialized when used within its own initialization [-Wuninitialized]
int* a = (int*) a;
gcc 7.1.1 has a warning for this -Winit-self:
warning: ‘a’ is used uninitialized in this function [-Wuninitialized]
int* a = (int*) a;
Note: Your cast is useless, C will promote any void * to the correct pointer type.
Related
I am trying to compile and run a simple C program from my Terminal. This is my code:
#include <stdio.h>
//integers that are 3n, 3n + 1, and 3n + 2
int main(){
int n,i,a,b,c;
scanf("%d", &n);
for (;n>0;n--) {
scanf("%d", &i);
if(n%3==0){a+=1;}
if(n%3==1){b+=1;}
if(n%3==2){c+=1;}
}
printf("%d %d %d", &a,&b,&c);
return 0;
}
After compiling it one time it generates this warning:
warning: format specifies type 'int' but the argument has type 'int *' [-Wformat]
I don't understand why it is generating that warning because I am not assigning any pointer variables. Why is it generating it?
Also, after compiling it a couple of times more my c file is turning into symbols. I don't understand why this is happening.
The name of my file is 73.c and this is how I'm compiling it on Terminal:
gcc 73.c -o 73.c
After that my file in converted to something like this (lines and lines of this):
œ˙Ì˛����Ä��������Ö� ��������H���__PAGEZERO��������������������������������������������������������(��__TEXT����������������������������������������������������__text����������__TEXT����������0�����˝�������0���������������Ä������������__stubs���������__TEXT����������.������������.��������������Ä�����������__stub_helper���__TEXT����������<�����$�������<���������������Ä������������__cstring�������__TEXT����������`������������`�����������������������������__unwind_info���__TEXT����������l�����H�������l������������������������������__eh_frame������__TEXT����������∏�����#�������∏��������������������������������Ë���__DATA��������������������������������������������������__nl_symbol_ptr�__DATA���������������������������������������������������__la_symbol_ptr�__DATA����������������������������������������������������H���__LINKEDIT������� ������������� ������`��������������������"��Ä0���� ����� ������������� �� ���# ��0���������∏ ����� !��#���
I really don't have any idea of what's going on. I've been at it for a long time now, I know it shouldn't be that hard but I really don't know what's wrong. Somebody have any idea of what might be happening?
There are two major things that are wrong here:
You try to print the address of variables a, b and c.
You invoke Undefined Behavior, but not initializing your
counters to 0.
You want to print the integers, so change this:
printf("%d %d %d", &a,&b,&c);
to this:
printf("%d %d %d", a, b, c);
I also added some spaces, but that's just to beautify the code, to make it more readable, it won't affect the execution.
You don't want to print the addresses! That's why you get the warning. Read more here: What is the difference between the * and the & operators in c programming?
As achelper, mentioned, you don't compile your program as you should (but that's not the problem of the code), but it's something you should get used to. I will demonstrate what I did to compile me program (I also like to use -Wall flag, which enables all warnings):
C02QT2UBFVH6-lm:~ gsamaras$ nano main.c
C02QT2UBFVH6-lm:~ gsamaras$ gcc main.c -Wall -o main
main.c:13:22: warning: format specifies type 'int' but the argument has type
'int *' [-Wformat]
printf("%d %d %d", &a,&b,&c);
~~ ^~
main.c:13:25: warning: format specifies type 'int' but the argument has type
'int *' [-Wformat]
printf("%d %d %d", &a,&b,&c);
~~ ^~
main.c:13:28: warning: format specifies type 'int' but the argument has type
'int *' [-Wformat]
printf("%d %d %d", &a,&b,&c);
~~ ^~
main.c:11:16: warning: variable 'c' is uninitialized when used here
[-Wuninitialized]
if(n%3==2){c+=1;}
^
main.c:5:16: note: initialize the variable 'c' to silence this warning
int n,i,a,b,c;
^
= 0
main.c:10:16: warning: variable 'b' is uninitialized when used here
[-Wuninitialized]
if(n%3==1){b+=1;}
^
main.c:5:14: note: initialize the variable 'b' to silence this warning
int n,i,a,b,c;
^
= 0
main.c:9:16: warning: variable 'a' is uninitialized when used here
[-Wuninitialized]
if(n%3==0){a+=1;}
^
main.c:5:12: note: initialize the variable 'a' to silence this warning
int n,i,a,b,c;
^
= 0
6 warnings generated.
C02QT2UBFVH6-lm:~ gsamaras$ ./main
2
1
2
1461300256 1461300252 1461300248C02QT2UBFVH6-lm:~ gsamaras$
In general, when in doubt, treat warnings as errors, so let's debug that code together, it will be fun. Pro-tip: Start from the first warning and resolve it. After that, the next warnings may be related, thus gone without having you really reading them!
After applying my suggestion, all the warnings related with what you described in your question are gone. Only the uninitialized variable ones are left.
That's easy, just initialize your variables to some initial value, like -1, if that makes sense of course.
In your case though, you use a, b and c as counters! So you must initialize them to 0, otherwise you are starting adding your values to garbage values, and that invokes Undefined Behavior!
So do change this:
int n,i,a,b,c;
to this:
int n, i, a = 0, b = 0, c = 0;
Without the initialization of the counters, I am getting, on my machine, now
C02QT2UBFVH6-lm:~ gsamaras$ ./main
2
1
2
1505029184 1 1C02QT2UBFVH6-lm:~ gsamaras$
You see that printf() gives me some garbage, while after initializing my counters to 0, I got:
C02QT2UBFVH6-lm:~ gsamaras$ ./main
2
1
2
0 1 1C02QT2UBFVH6-lm:~ gsamaras$
The points mentioned by gsamaras are correct, you should use :
printf("%d %d %d", a, b, c);
The syntax you were using is used in
scanf (pass address of the variable where the data is need to be filled.)
Also initialize variables while defining.
Regarding compilation:
The name -o specifies the output file generated after compilation thus it is overwriting your source code (i.e., 73.c).
If you omit -o, the default output file is generated as a.out. So for compiling you can use following and run the program as ./a.out:
gcc 73.c
man gcc quotes:
-o file
Place output in file file. This applies to whatever sort of output is being produced, whether it be an executable file, an object file, an assembler
file or preprocessed C code.
If -o is not specified, the default is to put an executable file in a.out, the object file for source.suffix in source.o, its assembler file in source.s,
a precompiled header file in source.suffix.gch, and all preprocessed C source on standard output.
I am currently working on a project including a somewhat generic linked list implementation using void pointers. Providing some utitily functions for these lists, I decided to make the identifying functions of elements only take (const void *).
After adding the const keyword were necessary, I thought about how correct my code is now (if I implemented everything as it should be before).
As the compiler (GCC) didnt warn me, I decided to take a test.
I compiled the following code with "gcc -g -Wall test.c" and received no warnings whatsover by GCC.
#include <stdio.h>
#include <stdlib.h>
void testf(const void *testp){
*((int32_t *) testp) += 1;
}
void testf2(const int32_t *testp){
*((int32_t *) testp) += 1;
}
int main(){
int32_t testv = 0;
printf("%i \n", testv);
testf(&testv);
printf("%i \n", testv);
testf2(&testv);
printf("%i \n", testv);
return 0;
}
The output is the following:
0
1
2
I did not expect that C would actually crash by this, but I expected to receive a warning by the compiler. In this example im only casting, in my real functions I'm also assigning the const void pointers to a tmp variable.
Is this a bug?
Given how sophisticated todays compilers are, Id atleast expect a warning that Im casting a pointer to a non const pointer. If I change the cast and add the const keyword there too, GCC throws the usual error that I try to assign to a read only location
Am I supposed to rethink my trust to functions declaring const pointers? This is not what I understand as a contract :)
Is this a bug?
No, it's not. By casting you are saying "I know what I am doing" to the compiler.
But GCC does have an option -Wcast-qual which would catch if a qualifier is casted away intentionally.
I compiled the posted code using:
gcc -c -ggdb -Wall -Wextra -pedantic -std=c99 filename.c -o filename.o
(the following list is abbreviated for ease of reading)
error: 'int32_t' undeclared
error: expected expression before ')' token
*((int32_t *) testp) += 1;
warning: unused parameter 'testp'
void testf(const void *testp){
with lots more warnings and errors regarding int32_t
Surely your compiler stated these same items.
BTW: The missing header file is stdint.h.
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 8 years ago.
Improve this question
I need someone to tell me what I am doing wrong over here.
void main(void) {
int *arr,n,i;
printf("Enter the number of elements you want to enter=");
scanf("%d",&n);
arr = (int*)calloc(n,sizeof(int));
if(!arr)
return;
for(i=0;i<n;i++)
scanf("%d",&arr[i]);
for(i=0;i<n;i++)
printf("%d ",arr[i]);
free(arr);
}
This is nothing but a simple program to input the number of items in an array then take the input and print the inputted values. But whenever I go to input the values in the array after taking the number of items from the user, my program CRASHES. I don't understand what I am doing wrong over here. Need some help immediately. Please run the program and see if it also crashes on other systems. I executed the program using an online compiler and strangely there it was running fine. I am using the Visual Studio 2013 command line compiler to execute my program.
Compiling this piece of code with gcc I get:
calloc.c: In function ‘main’:
calloc.c:4:5: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
calloc.c:5:5: warning: incompatible implicit declaration of built-in function ‘scanf’ [enabled by default]
calloc.c:7:17: warning: incompatible implicit declaration of built-in function ‘calloc’ [enabled by default]
calloc.c:18:5: warning: incompatible implicit declaration of built-in function ‘free’ [enabled by default]
using clang:
calloc.c:1:1: error: 'main' must return 'int'
void main(void) {
^
calloc.c:4:5: warning: implicitly declaring C library function 'printf' with type 'int (const char *, ...)'
printf("Enter the number of elements you want to enter=");
^
calloc.c:4:5: note: please include the header <stdio.h> or explicitly provide a declaration for 'printf'
calloc.c:5:5: warning: implicitly declaring C library function 'scanf' with type 'int (const char *, ...)'
scanf("%d",&n);
^
calloc.c:5:5: note: please include the header <stdio.h> or explicitly provide a declaration for 'scanf'
calloc.c:7:17: warning: implicitly declaring C library function 'calloc' with type 'void *(unsigned long, unsigned long)'
arr = (int*)calloc(n,sizeof(int));
^
calloc.c:7:17: note: please include the header <stdlib.h> or explicitly provide a declaration for 'calloc'
calloc.c:18:5: warning: implicit declaration of function 'free' is invalid in C99 [-Wimplicit-function-declaration]
free(arr);
^
4 warnings and 1 error generated.
As clang kindly pointed out, you need to add
#include <stdlib.h>
#include <stdio.h>
to the top of your code, as you are using functions that are declared within them. The functions you are using are in the standard C library, so the code will still compile but you should expect the unexpected. The reason your program crashes is likely to be that the compiler has made an incorrect assumption about the return type of calloc, as it doesn't have the correct declaration. Many systems will let you get away with this but at the very least they should warn you.
On a side note, please see this discussion on casting the return value of malloc (don't cast it). This advice also applies to calloc.
edit
Here's a minimal example which might shed some light on the issue:
a.c
#include <stdio.h>
int main()
{
printf("%f\n", f());
return 0;
}
b.c
float f()
{
return 4.2;
}
These two files can be compiled separately into object files:
gcc -c a.c # creates a.o
gcc -c b.c # creates b.o
No warnings or errors are generated. Switching to C99 mode causes an "implicit function declaration" warning. Note that at compile-time, the function definition isn't needed. These two object files can be linked:
gcc a.o b.o
Now, the linker finds the definitions of the functions so there is no error but it is already too late. The implicit declaration of f() when a.c was compiled causes the output to be incorrect when the program is run (I get 0.000000).
The same thing has happened here as in your question. The function calloc can be found, so there is no error at link-time. However, an incorrect assumption is made about the type that it returns, so it doesn't behave as expected on your system.
Why is the code below working? Should that be a compilation error (or at least a run-time error)?
#include <stdio.h>
int main(int argc, char** argv){
float *buf = "happy holiday"; // notice the float
printf("content of buf = %s\n",buf); //its working
return 0;
}
I compiled it and got just a warning:
~/Desktop/cTest>gcc -o run run.c
run.c: In function `main':
run.c:4: warning: initialization from incompatible pointer type
You should always compile with -Wall -Werror -Wextra (at a minimum). Then you get this:
cc1: warnings being treated as errors
test.c: In function 'main':
test.c:4: warning: initialization from incompatible pointer type
test.c:5: warning: format '%s' expects type 'char *', but argument 2 has type 'float *'
test.c: At top level:
test.c:3: warning: unused parameter 'argc'
test.c:3: warning: unused parameter 'argv'
It "works" because in practice, there's no difference between a char * and a float * under the hood on your platform. Your code is really no different to:
#include <stdio.h>
int main(int argc, char** argv){
float *buf = (float *)"happy holiday";
printf("content of buf = %s\n",(char *)buf);
return 0;
}
This is well-defined behaviour, unless the alignment requirements of float and char differ, in which case it results in undefined behaviour (see C99, 6.3.2.3 p7).
This program is not strictly conforming, a compiler is required to output a diagnostic and has the right to refuse to compile it. So don't do it.
This is an unfortunate behavior of gcc, and if somebody could get it fixed, we'd all be dealing with a lot less buggy software. Unfortunately there's a lack of will to fix many things like this. Submitting a bug report would not hurt.
This is a basic C code, which according to me should have thrown three errors (function not defined, function not returning anything, function argument missing). But to my surprise it threw nothing, it compiled and gave some garbage results:
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
int a=f1();
printf("a %d\n",a);
system("PAUSE");
return 0;
}
f1(int *t)
{
printf("t %d", t);
}
PS: I am using a gcc compiler on windows.
In C when a function is not declared is is assumed to return int and compilation continues (btw this can lead to nasty bugs). If the function is declared without a type (as f1() is in your code it is assumed to return int. Not returning a value from a non-void function (as in your code) is undefined behavior.
So none of the points you mention are required to cause a compilation error. Undefined behavior is not required to prevent your program from running - the program might run and might even produce good looking results.
Firstly, you were not compiling with warnings enabled. You should usually invoke gcc with at least the -Wall switch - for your example code, that gives:
x.c: In function 'main':
x.c:7: warning: implicit declaration of function 'f1'
x.c: At top level:
x.c:15: warning: return type defaults to 'int'
x.c: In function 'f1':
x.c:16: warning: format '%d' expects type 'int', but argument 2 has type 'int *'
x.c:17: warning: control reaches end of non-void function
Secondly, the reason that it compiles is that all of the errors in it are of a form called "undefined behaviour", which means that the compiler isn't required to diagnose them and stop compilation - it can simply produce garbage results.
You would probably be happier if you used gcc's -Wall option to enable all warnings. Then you would see this while compiling:
C:\test>make
gcc -Wall prog.c -o prog
prog.c: In function 'main':
prog.c:7:5: warning: implicit declaration of function 'f1'
prog.c: At top level:
prog.c:14:1: warning: return type defaults to 'int'
prog.c: In function 'f1':
prog.c:16:8: warning: format '%d' expects type 'int', but argument 2 has type 'int *'
prog.c:17:1: warning: control reaches end of non-void function
You can also use -Werror to turn all warnings in to errors (so you are forced to fix them).
Try compiling again with the -Wall flag. That turns on all warnings, then you'll see plenty:
c.c: In function ‘main’:
c.c:7: warning: implicit declaration of function ‘f1’
c.c: At top level:
c.c:15: warning: return type defaults to ‘int’
c.c: In function ‘f1’:
c.c:16: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘int *’
c.c:17: warning: control reaches end of non-void function
Since you don't have any compile time errors, just warnings, the code compiles fine. It just won't execute very well.
f1 is considered to have the implicit prototype 'int f1(int)'.
Hence the call is valid.
f1 does not return anything whereas it is implicitly suppoed to return an int: the behaviour is undefined.
The compiler could warn you that the implicit prototype does not agree with the definition. It could also ask for a proper return. This is part of the checks that the static analysis inside the compiler could perform: gcc does not do it, others may.
In any case compilers usually do not guarantee anything about non ISO conforming programs.
If you add -Wall to your gcc commands you should get some warnings. I guess it works as old style C had loose function prototyping. And will assume unknown functions return int. The linker worked because there were no undefined symbols (f1 exists) but you got garbage as what was passed on the stack (i.e. nothing) was not what was expected.