Why does this compile in VS 2015 but not in IDEOne? - c

#include <stdio.h>
void foo(void);
void foo(int repeatCount) {
int i;
for (i = 0; i < repeatCount; i++) {
printf("\nHello World\n");
}
}
int main(int argc, char *argv[]) {
printf("main");
}
This is intended to be C, not C++. The file in VS is saved as a .c file, the program in IDEOne is configured as a C file.
The prototype doesn't match the function definition.
However, it does compile in VS 2015. Warning Level 3 does give a warning.

Because VS studio doesn't conform to the Standard C and uses its own compiler.
With Standard C you should see something like this:
gsamaras#gsamaras-A15:~$ gcc -Wall main.c
main.c:5:6: error: conflicting types for ‘foo’
void foo(int repeatCount) {
^
main.c:3:6: note: previous declaration of ‘foo’ was here
void foo(void);
^
main.c: In function ‘main’:
main.c:14:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
What compiler does VS use?
The compiler is named as Microsoft C/C++ Compiler. The cl.exe is a tool that controls the Microsoft C and C++ compilers and linker. There are other compilers you can use: Intel C and C++ Compilers, which is automatically configured in Visual Studio after installation.

Related

Catching Missing Semicolons in C header file prototypes

This topic ought to have been flogged to death. I just spent 30 minutes locating what ended up being a missing semicolon at the end of a function prototype in a header file:
void foo(void);
void bar(void) // <<< Error on this line
void squee(void);
This is a common typo caused by copy-pasting the prototype from the C file. Of course according to the compiler the universe just fell apart, with an endless stream of absolutely nonsensical errors, none of them helpful.
This could be avoided by having an optional parsing phase to check for this condition in .h files then report a warning (promoted to error if settings mandate). This would require some restrictions on what you put in header files (no code, consistent format for prototypes, etc). But that's an easy compromise.
I can write my own SW tool to do this, but it would be more helpful to run it as a part of the build process. I use GCC in Eclipse. Any advice on where you'd start with this? Or anything pre-existing / off the shelf? Or perhaps just a better way to approach it?
Thank you.
it's far more common and more difficult to guess the following problem (in a header file):
struct something {
type1 var1;
type2 var2;
}
/* EOF */
and when you #include "header.h" into hello.c
#include <stdio.h>
#include "header.h"
int main(int argc, char **argv)
{
printf("Hello, world\n");
}
you get an error e.g.
lcu#europa:~$ gcc main.c
main.c:4:1: error: expected ';', identifier or '(' before 'int'
4 | int main(int argc, char **argv)
| ^~~
and the compiler has got out of header.h to signal the error in the line of main function. The thing can be worse if you happen to use legacy code and declare main() the old way:
main(argc, argv)
char **argv;
{
...
because then, the struct is a valid type and it is taken as the type returned by main() and you get (if you get it) the error far below (or no error at all, just a warning):
lcu#europa:~$ gcc main.c
main.c: In function 'main':
main.c:4:1: warning: type of 'argc' defaults to 'int' [-Wimplicit-int]
4 | main(argc, argv)
| ^~~~
In this case, the contents of main.c were:
#include <stdio.h>
#include "header.h"
main(argc, argv)
char **argv;
{
printf("Hello, world\n");
}
which is still valid c code.
(these examples were made by gcc, because clang ---the native compiler of freebsd--- detects the EOF in the header file and shows a warning stating that the type was not ended before the end of the include file. But this only happens if the type definition is the last of the file.
Note:
if you declare main as:
#include <stdio.h>
#include "header.h"
main(argc, argv)
int argc;
char **argv;
{
printf("Hello, world\n");
}
you get a complete compilation, without even a warning.

Why can I have differing signatures for a function's definition and declaration?

Consider the following program (inspired by the Tcl source code here):
test.h
void func(char* format, ...);
test.c
#include <stdio.h>
#define func funcDummy
#include "test.h"
#undef func
void func(char *format, char *arg)
{
printf(format, arg);
}
main.c
#include "test.h"
int main(int argc, char *argv[])
{
(void) argc;
(void) argv;
func("I'm %s\n", "confused");
return 0;
}
This compiles with no warnings using gcc main.c test.c -Wall -Wextra and outputs "I'm confused."
I would expect to see an error about there being an unresolved reference to function func. What's going on that makes this okay?
This works because C doesn't have mangled names. In C, the symbol name is 'func'. In C++, the symbol name would be somethings like '_Zblahblah_func_blahblah_E'. C++ encodes the arguments into the symbol name (used by the linker later). C does not.
test.c defines the function void func(char *format, char *arg).
when compiling main.c, the compiler sees: 'void func(char* format, ...);'
The linker however, will refer to both as simply 'func'. When the linker sees the call in main.c, it sees the definition for func as simply 'func' (args be damned).
It just so happens, that the args you've passed to it in main.c, happen to be compatible with those expected in func.c, and so it magically works.
If you were instead to change the files to 'cpp' instead of 'c', you'll have a linker error (since the mangled names for both prototypes, will not match, and you'll have a linker error)
TL;DR: C++ supports function overloading, C does not.

Undeclared Identifier C Programming in Visual C++

So I'm creating a simple program, and I usually use the GNU compiler.
However, this time I chose to use Visual C++ for developing in C.
I've set up my project correctly, changing the settings to make it compile in C. The code is very simple:
#include <stdlib.h>
#include <stdio.h>
int main(){
printf("Hey!");
int x = 9;
printf("%d",x);
return 0;
}
If I compiled this using Code::Blocks IDE and the GNU compiler, it would work, but for some reason it doesn't work in Visual C++. I keep getting these errors:
error C2143: syntax error : missing ';' before 'type'
error C2065: 'x' : undeclared identifier
How can I fix this?
VC++ 2010 only implements C89/C90, not the newer C standards that allow variable declarations after other statements inside of a function body. To fix it, move the declaration of x to the beginning of main:
#include <stdlib.h>
#include <stdio.h>
int main() {
int x = 9;
printf("Hey!");
printf("%d",x);
return 0;
}
Change the file extension to .cpp

No warning or error indication when variable defined as static but declared as extern

I came across some code today that surprised me. A variable was defined (outside of a function) in the .c file as being static. However, in the .h file it was declared as being extern. Here is a similar example of the code:
Structure definitions and declaration in .h:
typedef struct
{
unsigned char counter;
unsigned char some_num;
} One_Struct;
typedef struct
{
unsigned char counter;
unsigned char some_num;
const unsigned char * p_something;
} Another_Struct;
typedef struct
{
One_Struct * const p_one_struct;
Another_Struct * const p_another_struct;
} One_Useful_Struct;
extern One_Useful_Struct * const p_my_useful_struct[];
Definition and initialization in .c:
static One_Useful_Struct * const p_my_useful_struct[MAX_USEFUL_STRUCTS] =
{
&p_my_useful_struct_regarding_x,
&p_my_useful_struct_regarding_y,
};
Question:
So my question is, why didn't I receive a compiler error or warning?
The code has been successfully running in other projects for some time now. I did note that the pointer is never used outside of the .c file in which it is defined and was properly defined as static (I removed the external declaration). The only reason that I found it was because I ran Lint on the project and Lint picked it up.
It's certianly not standard C. GCC and clang both detect and give an error on this case:
$ gcc example.c
example.c:4: error: static declaration of ‘x’ follows non-static declaration
example.c:3: error: previous declaration of ‘x’ was here
$ clang example.c
example.c:4:12: error: static declaration of 'x' follows non-static declaration
static int x;
^
example.c:3:12: note: previous definition is here
extern int x;
^
1 error generated.
You must be using a pretty permissive compiler - maybe Visual Studio? I just checked on my Windows machine and VS2003 accepts my example program silently. Adding /Wall does give a warning:
> cl /nologo /Wall example.c
example.c
example.c(4) : warning C4211: nonstandard extension used : redefined extern to static
Looks to me like you're using an extension of whatever compiler it is that you're using.

GCC/C++ cannot link libraries

I am just a beginner in C++. I am trying to construct some header file header.h, but the output is always like the following:
/tmp/ccTmZKXX.o: In function `main':
main.c:(.text+0x13): undefined reference to `func'
collect2: ld returned 1 exit status
Could you please help me to see whether my way of using header file is correct or not? Thanks a lot!
Main code (main.c):
#include "stdio.h"
#include "func.h"
main() {
double a = f(2.3);
printf("a=%f\n", a);
}
where func.c contains:
double func (double x) { return x ;}
where func.h contains:
double func (double);
And I compile with:
gcc -o main main.c
There are multiple problems here:
The C++ compiler in the GCC (GNU Compiler Collection) is g++, not gcc; the latter is the GNU C Compiler.
The code in main.c is a (not very good) C program and not a C++ program. C99 outlawed the implicit int return type; C++ essentially never allowed it.
Your question uses a function f; your compilation error references func. This means you did not show us exactly the code you tried to compile.
The standards say #include <stdio.h>; you should too.
#include <stdio.h>
#include "func.h"
int main()
{
double a = func(2.3);
printf("a=%f\n", a);
}
NB: This is a perfectly good C program if you work with C99. In C89, you are expected to return a value from main() rather than 'fall off the end'. C99 follows C++98 and allows falling off the end as equivalent to an explicit return 0;. I tend to put the explicit return(0); (usually with, sometimes without, the parentheses - the compilers don't mind either way) anyway. (I compile C with -Wstrict-prototypes; to get a warning-free compilation, I write int main(void), which also works with C++ but the void is not necessary there.)
The header is OK, though you will learn in due course about header guards and other paraphernalia that make headers more reliable.
#ifndef FUNC_H_INCLUDED
#define FUNC_H_INCLUDED
extern double func(double a);
#endif /* FUNC_H_INCLUDED */
The extern is not mandatory. I tend to use it, but there are many who do not.
The source file defining the function should include the header to ensure that the function definition is consistent with the declaration. All code that uses the function should include the header so that there is a prototype in scope. This cross-checking is crucial for reliability. C++ requires prototypes in scope before a function is used; it does not demand a prototype in scope before the function is defined (but it is good practice to do so). It is strongly recommended in C that you have a prototype in scope before defining an external (non-static) function. You can use -Wmissing-prototypes with C code and GCC to spot such problems, but the option is not valid for G++.
#include "func.h"
double func(double x) { return x; }
Since this is a C++ question, we could consider inlining the function in the header. Indeed, C99 also supports inline functions. However, we can ignore that for the time being.
Since this is a C++ question, we could consider that using <stdio.h> is not good because it is not type safe. You might be better off using <iostream> et al, not least because they are type safe.
#include <iostream>
#include "func.h"
int main()
{
double a = func(2.3);
std::cout << "a=" << a << std::endl;
}
The correct compilation requires both the main program and the function it invokes, so you might write:
g++ -o main main.c func.c
Or, if you are compiling it in C, then:
gcc -std=c99 -o main main.c func.c
Note that the -std=c99 is necessary to ensure that the absence of return in main() is acceptable.
Note that there are several extensions in use for C++ source code, including .C, .cpp and .cxx, all of which are accepted by G++ (as well as .c).
There are several things wrong here.
Define the function as follows in func.h
extern double func(double);
When compiling, provide all source (c, cpp) files
gcc main.c func.c -o main
You should be good to go.
Compile like this:
gcc -o main main.c func.c
Then it will be fine.

Resources