Why no GCC warning for re-definition of struct in C? - c

main.h
struct tagname {
int m1;
int m2;
};
main.c
#include "main.h"
int main(void) {
struct tagname d1;
d1.m1 = 7;
struct tagname {
float s1;
float s2;
float s3;
};
struct tagname e1;
e1.s1 = 0;
}
I am using XC16 v1.60 (which I believe uses GCC v4.5.1 as the base) with -Wall, -Wextra, -Wshadow, and a host of other flags which I don't think are relevant, and I would have thought (hoped?) that the compiler would issue a warning here. What am I missing?
Edit: Apologies, I have updated the question with the extra detail desired.

C allows new declarations of identifiers in new scopes. When you declare a function or start a compound statement with {, that starts a new scope. Iteration and selection statements also start new scopes. Inside a new scope, a new declaration of an identifier generally hides the previous declaration. Since this is legal C, the compiler allows this.
In GCC 4.5.1, the documentation for -Wshadow says it warns “whenever a local variable shadows another local variable, parameter or global variable or whenever a built-in function is shadowed.” A structure tag is not a local variable or a built-in function.
Incidentally, the return type of main should be int except in special situations; using int main(void) or int main(int argc, char *argv), not void main(void).

Related

why volatile can repeat declare?

#include <stdio.h>
volatile int isInit_STD;
volatile int isInit_STD;
int main() {
printf("v-%d-addr%x\n",isInit_STD,&isInit_STD);
isInit_STD = 1;
printf("v-%d-addr%x\n",isInit_STD,&isInit_STD);
return 0;
}
and the result is:
v-0-addr387fd040
v-1-addr387fd040
why volatile can repeat declare?
It turns out they are all the same, the same address.
If one of them deletes the 'volatile', that can't be compiled success.
I want to know the reason, looking forward to your reply.
The C standard says that (C17 6.7/4)
All declarations in the same scope that refer to the same object or function shall specify compatible types.
That means that as long as you use the same name, same type and same type qualifiers (volatile etc), you can declare the variable as many times as you like, and it will all refer to the same object.
And the opposite: if you use different types or qualifiers, but give the variable the same name, it is a constraint violation and the compiler must issue a diagnostic message.
Apart from what standard C allows, common sense states that we should avoid having multiple declarations of the same variable when possible. Good program design practices also state that we should avoid declaring objects at file scope, or if that's not possible, avoid using external linkage ("globals") and instead enforce interal linkage by declaring the variable static.
I want to know the reason
You can repeat a declaration of anything as many times as you want, as long as the declarations are "the same". It's not specific to volatile, just there has to be no conflict. All declarations refer to the same thing.
The following is an actual whole .c file:
// 3 declarations of function main.
int main();
int main();
int main();
// 3 declarations of struct A type.
struct A;
struct A;
struct A;
// 3 declarations of variable a
extern volatile int a;
extern volatile int a;
extern volatile int a;
// 3 declarations of variable b
int b;
int b;
int b;
// 3 declarations of variable c
volatile int c;
volatile int c;
volatile int c;
// example with conflicts:
int d;
// volatile int d; // error - conflict with above, d is not volatile
// static int d; // error - conflict with above, d is not static
extern int d; // Fine! Stuff declared at file scope is implicitly extern.

OOP and forward declaration of structure in C

I am studying C language and have recently learned how to write the OOP using C. Most part of it was not hard that much to understand for me except the name of structures type used to create new class.
My textbook used struct dummy_t for forward declaration and typedef struct {...} dummy_t for its definition. In my understanding, these are two different type because the former is struct dummy type and the later is struct type without a name tag but the sample code from the textbook worked well.
So I deliberately modified the sample code so that the difference in the names of structures will be much clearer. Below are the lines of code I tried.
//class.h
struct test_a;
struct test_a * test_init(void);
void test_print(struct test_a*);
//class.c
#include <stdio.h>
#include <stdlib.h>
typedef struct dummy{
int x;
int y;
} test_b;
test_b * test_init(void){
test_b * temp = (test_b *) malloc(sizeof(test_b));
temp->x = 10;
temp->y = 11;
return temp;
}
void test_print(test_b* obj){
printf("x: %d, y: %d\n", obj->x, obj->y);
}
//main.c
#include "class.h"
int main(void){
struct test_a * obj;
obj = test_init();
test_print(obj);
return 0;
}
// It printed "x: 10, y: 10"
As you can see, I used struct test_a for forward declaration and typedef struct dummy {...} test_b for definition.
I am wondering why I did not get the compile error and it worked.
I am wondering why I did not get the compile error
When you compile main.c the compiler is told via a forward declaration from class.h that there is a function with the signature struct test_a * test_init(void);
The compiler can't do anything other than just trusting that, i.e. no errors, no warnings can be issued.
When you compile class.c there is no forward declaration but only the function definition, i.e. no errors, no warnings.
It's always a good idea to include the .h file into the corresponding .c file. Had you had a #include "class.h" in class.c the compiler would have been able to detect the mismatch.
..and it worked
What happens is:
A pointer to test_b is assigned to a pointer to test_a variable
The variable is then passed as argument to a function expecting a pointer to test_b
So once you use the pointer it is used as it was created (i.e. as pointer to test_b). In between you just stored in a variable of another pointer type.
Is that ok? No
Storing a pointer to one type in a object defined for another pointer type is not ok. It's undefined behavior. In this case it "just happened to work". In real life it will "just happen to work" on most systems because most systems use the same pointer layout for all types. But according to the C standard it's undefined behavior.
It 'worked' because you did not include class.h in class.c. So the compiler can't see the implementation does not match the declaration.
The proper way is (but without the typedef for clarity):
// class.h
struct test_a;
struct test_a* test_init(void);
//class.c
#include "class.h"
struct test_a {
int x;
int y;
};
struct test_a* test_init(void)
{
...
}
The struct test_a in the header file makes the name test_a known to the compiler as being a struct. But as it does not now what is in the struct you can only use pointers to such a struct.
The members are defined in the implementation file and can only be used there.
If you want to use a typedef:
// header
typedef struct test_a_struct test_a;
test_a* test_init(void);
//implementation
struct test_a_struct {
int x;
int y;
};
test_a* test_init(void)
{
...
}

Why Frama-C v20.0 Calcium does not support redefinition of a typedef in a non-global scope

I am trying to analyze the following C program:
#include <stdio.h>
typedef struct a {
int x;
char y;
} alias;
int main()
{
typedef struct b {
int x;
int y;
} alias;
alias *var = (unsigned long*) 0x12345678;
var->y = 0x00;
return 0;
}
As typedef is redefined in function "main", I followed the user manual of Frama-C and used the option -c11.
-c11 allows the use of some C11 constructs. Currently supported are typedefs redefinition
However, I got the following error:
redefinition of a typedef in a non-global scope is currently
unsupported
Could you please help me explain this case?
Note that I don't have this problem if I use v12.x - Magnesium.
It seems frama-c does not support redefining a typedef symbol in a local scope.
The C Standard allows this, and it might be useful to support automatically generated code, but doing this on purpose seems a good way to create confusion for readers and maintainers of the code.

My dev++ is returning non-static warning. Whats the problem with the code?

I'm doing this code and can't find a way to compile. Tried Online compilers which each one of them gives a different reason for the error, my Dev++ says that
[Warning] non-static data member initializers only available with -std=c++11 or -std=gnu++11
Every online compiler and cant find an error on code either
#include <stdio.h>
#include <stdlib.h>
struct uninter
{
char nome[5] = {'L','U','C','A','S'};
int RU = 2613496;
}; struct uninter aluno;
int main() {
int i;
printf("\n Nome do Aluno: ");
for (i = 0; i < 5; i++ ){
printf( "%c\n", aluno.nome[i]);
}
printf("\n RU do aluno: %d \n ", aluno.RU);
system("pause");
return 0;
}
[Warning] non-static data member initializers only available with -std=c++11 or -std=gnu++11
The warning message you are receiving is because you are compiling your code with a C++ compiler. Probably with with -std=c++98 or -ansi or otherwise implicitly using the 1998 standard.
You are trying to create a default initializer for a member of a struct, which is a feature not added to C++ until the 2011 standard. To compile a C++ program with this feature without the compiler warning you about this, you need to pass in the -std=c++11 or -std=gnu++11 flags to the compiler command as the warning states.
If this is expected to be C code rather than C++ code, default initializers for structs are simply not a part of the language. You can initialize its member variables upon declaration of an object of that struct's type.
An example of how you might do this with a C compiler:
// definition of the struct
struct uninter
{
char nome[5];
int RU;
};
// declaration of an instance of an object of type struct uninter
struct uninter x = {{'L','U','C','A','S'}, 2613496};
// alternative declaration if using C99 standard with designated initializers
struct uninter y = {
.nome={'L','U','C','A','S'},
.RU= 2613496
};
in general, cannot initialize a struct contents in C in the definition of the struct. Suggest something similar to:
struct uninter
{
char nome[5];
int RU;
};
struct uninter aluno = {.nome = "LUCAS", .RU = 2613496};
The problem with the code is that it is using non-static data member intializers:
struct uninter
{
char nome[5] = {'L','U','C','A','S'};
int RU = 2613496;
}; struct uninter aluno;
... which is a C++11 feature, and therefore isn't portable unless you are using a C++11 (or later) compiler. (It might still compile under older compilers, if they have that feature enabled as a compiler-specific extension, but they are politely warning you that you can't expect it to compile everywhere)
If you don't want your program to require C++11 or later to compile, the easiest thing to do would be to rewrite it so that the struct's member variables are initialized via a different mechanism. For example (assuming your c tag is intentional) you could have an init-method do it for you:
struct uninter
{
char nome[5+1]; // +1 for the NUL/terminator byte!
int RU;
}; struct uninter aluno;
void Init_uninter(uninter * u)
{
strcpy(u->nome, "LUCAS");
u->RU = 2613496;
}
[...]
int main() {
int i;
Init_uninter(&aluno);
[...]
... or if you actually intended to specify/use a pre-C++11 version of C++, a default-constructor would do the trick a bit more gracefully:
struct uninter
{
uninter()
{
strcpy(nome, "LUCAS");
RU = 2613496;
}
char nome[5+1]; // +1 for the NUL terminator byte!
int RU;
}; struct uninter aluno;

Is There C Syntax For Function Pointer From Function Declaration

Instead of declaring a function pointer typedef for a function, is it possible to get it from the function declaration?
Typically,
int foo(int x);
typedef int (*fooFunc)(int);
fooFunc aFunc;
What I want:
int foo(int x);
foo* aFunc;
I want to use it for dlsym:
foo* aFunc;
aFunc = dlsym(lib, "foo");
aFunc(x);
If I update foo and forgot to update fooFunc, or vice versa, that would be bad. Also, I may have many functions and it would be more work to maintain both the function declarations and the function pointer typedefs that are associated with those functions.
Conclusion:
AndreyT's answer is the most portable but if you code for gcc then typeof is a great solution.
If you are talking about a declaration specifically, i.e. a non-defining declaration of a function, you can remove the redundancy by defining a typedef-name for function type and using it in both cases - to declare the function itself and to declare a pointer to it, like this
typedef int FuncType(int); /* <- function type */
FuncType foo; /* <- declaration of `int foo(int)` */
FuncType *aFunc; /* <- definition of `int (*aFunc)(int)` */
I.e. typedef-names can be used in non-defining function declarations. However, you can't use a typedef name in function definition, meaning that later you'll still have to do
int foo(int x) /* <- no way to use the above `FuncType` here */
{
/* whatever */
}
which basically renders the above trick virtually useless.
Of course, this doesn't help you to generate a pointer from an existing non-modifiable function declaration, if that's your situation.
If you have gcc, typeof works.
Update
$ cat fxf.c
#include <stdio.h>
int main(int argc, char **argv) {
typedef __typeof__ (main) function_of_same_type_as_main_t;
function_of_same_type_as_main_t *f;
printf("main() called.\n");
f = main;
if (argc) f(0, NULL);
return 0;
}
$ /usr/bin/gcc -std=c89 -pedantic -Wall -Wextra -o fxf fxf.c
fxf.c:3: warning: unused parameter ‘argv’
$ ./fxf
main() called.
main() called.
Simple answer: no, that doesn’t work. foo is a specific function which has a prototype (int (int)). Using foo in the way you did would be a bit like using an int to declare another int:
4 x; // expect this to be the same as int x
That said, there might be compiler extensions which make that work. I know that the upcoming C++ standard will have the decltype keyword to allow that. Using that, the following might work (untested, since I don’t have a supporting compiler handy):
int foo(int x);
decltype(&foo) aFunc = dlsym(lib, "foo");
It is not possible. However, you can write some code that would generate a warning, so that you would catch type mismatch. The following code generates an assignment from incompatible pointer type warning.
#include <stdio.h>
int foo(int, int);
typedef int(*fooFunc)(int);
fooFunc myfunc;
int foo(int x, int y)
{
return 2*x + y;
}
int main(int argc, char **argv)
{
myfunc = foo;
printf("myfunc : 0x%x\n", (unsigned int)myfunc);
return 0;
}
Of course, this means you would have to write this test code where the foo function is visible, so this is still more code to add for each function type. The solution here is probably a code generator, that would generate a proper header file containing both functions and their associated typedefs
Not quite the same, but you can typedef the function and use it for both the prototype and the pointer.
typedef int fooFunc(int);
fooFunc foo;
fooFunc *aFunc;

Resources