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.
Related
According to the OpenCV documentation cvLoadImage must return pointer to IplImage, but it looks like it is returning int.
when I run the below program, i get some warnings which is shown below program
#include "highgui.h"
#include <stdio.h>
int main(int argc, char** argv)
{
IplImage *img = cvLoadImage ("/path/to/file/face.jpg");
if(img != NULL)
printf("%d", img->width);
}
Also I am getting segmentation fault when I run the above code, I am guessing since img is a int so its causing crash when I am trying to access img->width, Warnings when above code is compiled
/usr/local/Cellar/opencv/3.3.0_3/include/opencv2/core/types_c.h:929:13: warning:
implicit declaration of function 'cvRound' is invalid in C99
[-Wimplicit-function-declaration]
ipt.x = cvRound(point.x);
^
main.c:7:21: warning: implicit declaration of function 'cvLoadImage' is invalid
in C99 [-Wimplicit-function-declaration]
IplImage *img = cvLoadImage ("/path/to/file/face.jpg");
^
main.c:7:15: warning: incompatible integer to pointer conversion initializing
'IplImage *' (aka 'struct _IplImage *') with an expression of type 'int'
[-Wint-conversion]
IplImage *img = cvLoadImage ("/path/to/file/face.jpg");
warning says incompatible converstion from int, so I have change the IplImage to int and it worked fine and it ourputs some negative integer value for img
#include "highgui.h"
#include <stdio.h>
int main(int argc, char** argv)
{
printf("%s\n","hello world");
int img = cvLoadImage ("/path/to/file/face.jpg");
printf("%d", img);
}
I get the below warnings for the above program
implicit declaration of function 'cvRound' is invalid in C99
[-Wimplicit-function-declaration]
ipt.x = cvRound(point.x);
^
main.c:7:15: warning: implicit declaration of function 'cvLoadImage' is invalid
in C99 [-Wimplicit-function-declaration]
int img = cvLoadImage ("/path/to/file/face.jpg");
I went sleepless to figure out it, google could not help, is it something to do with OpenCV versions or C versions?, I am using Opencv2 3.3.0, please feel free to ask if any information is required
There's nothing wrong with the first code and should run fine if compiled with g++ instead of gcc.
The second code you're implicitly converting from IplImage* to int which is wrong and will not run.
The warning and errors regarding cvRound() function has to do with OpenCV C API which hasn't been updated in a while and will most likely be removed in a future version. Most of the new OpenCV functionalities are only present in the C++ API.
Other posts which have mentioned errors regarding cvRound() function in the C API:
https://github.com/opencv/opencv/issues/6076
https://github.com/opencv/opencv/issues/8438
https://github.com/opencv/opencv/issues/8658
In the future try to use OpenCV C++ API for best possible results.
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.
I have some code that compiled fine under GCC 4.8.4. I've recently upgraded my system and now have GCC 5.2.1, and I'm getting a warning about incompatible pointer types. I've extracted the problem to a small example that reproduces the error:
typedef const double ConstSpiceDouble;
void foo(const double (*)[3]);
int main(int argc, char **argv) {
double a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};
foo((ConstSpiceDouble (*)[3])a);
return 0;
}
In the real code, the typedef, the function definition, and the type cast are in a library outside of my control otherwise I would just fix the cast and the function to match. Here's the message I get from the compiler:
$ gcc -Werror -c test.c
test.c: In function ‘main’:
test.c:9:7: error: passing argument 1 of ‘foo’ from incompatible pointer type [-Werror=incompatible-pointer-types]
foo((ConstSpiceDouble (*)[3])a);
^
test.c:4:6: note: expected ‘const double (*)[3]’ but argument is of type ‘const ConstSpiceDouble (*)[3] {aka const double (*)[3]}’
void foo(const double (*)[3]);
^
cc1: all warnings being treated as errors
The note from gcc is especially troubling since it seems to admit that the two types are identical, yet it complains anyway.
The consensus here and elsewhere seems to be that GCC is doing something unexpected with the const and the typedef. I don't know that unexpected necessarily equates to a bug, but that's for the GCC devs to determine.
I have solved my compilation problem by defining a macro for the function call that fixes the non-matching typecast that's inside the library. I generally dislike tinkering with library internals, but the macro allows me to not touch the actual library header and define it in my own code where it can be commented for the future, and test coverage of that code should be a reasonable early warning signal if the underlying library changes in such a way that the macro breaks something down the road.
This isn't so much "solved" as "worked around", but any further insight will likely have to come from the GCC devs.
If you type cast 'a' to be ConstSpiceDouble, GCC is doing something unexpected with the const and the typedef, by which eventually the type becomes 'const const double'. This you can see in the error message "const ConstSpiceDouble", which equates to 'const const double', this does not work.
Solution is to either say 'a' is const double or to say 'a' is ConstSpiceDouble before you parameter 'a' to the foo function
typedef const double ConstSpiceDouble;
void foo(const double (*)[3]);
int main(int argc, char **argv) {
const double a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};
// or ConstSpiceDouble a[3][3] = {{1,2,3},{1,2,3},{1,2,3}};
foo(a);
return 0;
}
The 'const' pre-pending seems to be a new feature in the latest versions of gcc, but of that, I am not sure :(
I have something along the lines of:
#include <stdio.h>
typedef struct {
char s[100];
} literal;
literal foo()
{
return (literal) {"foo"};
}
int main(int argc, char **argv) {
printf("%s", foo().s);
return 0;
}
And I get this error when compiling it (with gcc):
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2
has type ‘char[100]’ [-Wformat=]
any1 has any ideas on how I can fix it? And what is wrong with that function return type?
EDIT
The problem (if not clear in the discussion) was the c standard gcc was using to compile the file. if you use -std=c99 or -std=c11 it works.
It is not an error but a warning, not all warnings that -Wall produces are sensible.
Here the compiler is "kind-of" right: before evaluation your argument is an array and not a pointer, and taking the address of a temporary object is a bit dangerous. I managed to get rid of the warning by using the pointer explicitly
printf("%s\n", &foo().s[0]);
Also you should notice that you are using a rare animal, namely an object of temporary lifetime, the return value or your function. Only since C99, there is a special rule that allows to take the address of such a beast, but this is a corner case of the C language, and you would probably be better off by using some simpler construct. The lifetime of the pointer ends with the end of the expression. So if you would try to assign the pointer to a variable, say, and use it later on in another expression, you would have undefined behavior.
Edit(s): As remarked by mafso in a comment, with C versions from before C99, it was not allowed to take the address of the return value of the function. As Pascal Cuoq notes, the behavior of your code is undefined even for C99, because between the evaluation of the arguments and the actual call of the function there is a sequence point. C11 rectified this by indroducing the object of temporary lifetime that I mentioned above.
I don't exactly why maybe someone with more knowledge in C than me can explain it but writing main() on this way:
int main(int argc, char **argv) {
literal b = foo();
printf("%s", b.s);
return 0;
}
The code prints "foo" correctly on GCC 4.5.4
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.