About Use Of Storage Classes in C - c

The following code displays an error if the Storage Class of the parameters of the function int *check(register int,register int); declared as some other Storage Class.
I compiled this code on Code::Blocks 10.05 IDE with GNU GCC Compiler. What is the reason behind the error? Is it a compiler specific error or a general one?
The code section begins from here:
int *check(register int, register int);
int main()
{
int *c;
c = check(10, 20);
printf("%d\n", c);
return 0;
}
int *check(register int i,register int j)
{
int *p = i;
int *q = j;
if(i >= 45)
return (p);
else
return (q);
}

int *check(register int i,register int j)
{
int *p=i;
int *q=j;
Type mismatch of p q and i j. Perhaps what you want is :
int *check(int i, int j)
{
int *p=&i;
int *q=&j;
Correction: Note that register cannot be used with &. Besides, the keyword register has little usage because the compiler usually ignores it and does the optimization itself.

int *check(register int i,register int j)
{
int *p=i;
int *q=j;
if(i >= 45)
return (p);
else
return (q);
}
While register storage class specifier is allowed on parameter declaration, parameters i and j have int type while p and q are of type int *. This makes the declaration of p and q invalid.
You cannot just change this to:
int *p=&i;
int *q=&j;
as the & operator does not allow you to have an operand of register storage class.
You cannot also also change the parameter declaration from register int i and register int j to int i and int j and then return the address of i and j object as their lifetime ends at the exit of the function.
In your case you should just not use pointers: use int parameters and an int return value.

First type mismatch:
int *p=i;
int *q=j;
Second side note & not applied/valid on register variables.
From: address of register variable in C and C++
In C, you cannot take the address of a variable with register storage. Cf. C11 6.7.1/6:
A declaration of an identifier for an object with storage-class specifier register
suggests that access to the object be as fast as possible. The extent to which such
suggestions are effective is implementation-defined.
third: Returning address of local object is Undefined behavior (and parameters of functions counts in local variables). Don't return address of that there life is till function returns.
Suggestion:
To return address, you need to do dynamic allocation and return address of that. for example:
int *check(int i,int j){
int *p= malloc(sizeof (int));
int *q= malloc(sizeof (int));
*p = i;
*q = j;
if(i >= 45){
free(q);
return (p);
}
else{
free(p);
return (q);
}
}
Note returned address is not of i, j, but its address of dynamically allocated memory. Don't forget to call free(a) in main().

In my machine with GCC 4.7.3 on Ubuntu 13.04, the output is
$gcc test.c
test.c: In function ‘main’:
test.c:7:3: warning: incompatible implicit declaration of built-in function ‘printf’ [enabled by default]
test.c:7:3: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘int *’ [-Wformat]
test.c: In function ‘check’:
test.c:13:12: warning: initialization makes pointer from integer without a cast [enabled by default]
test.c:14:12: warning: initialization makes pointer from integer without a cast [enabled by default]
$./a.out
20
It accepts the program with a lot of warnings. And there is not a single word says "storage class". so I wonder what version of GCC you are using?
The first two warnings can be fixed by #include <stdio.h> and change %d in the printf function call to %p. Let's ignore those for now and focus on the rest two. Depends on what you want to do, you can have different options to eliminate them.
If you want to return the address of i or j as a stack based variable (which is unusual because it is invalid after return to the caller), you can do
int *check( int i, int j)
{
int *p = &i;
int *q = &j;
...
You cannot obtain the address of a register variable, so you have to remove them. In this case, with your main function your program will print something like 0x7fffc83021f8 in my machine. That is the pointer value to the variable j, although it is not valid at the time we prints it, as long as you do not attempt to dereference it everything is OK.
If this is not what you want, you probably want to force the integer i or j to represent a pointer, then you need to do
int *check(register int i,register int j)
{
int *p=(int *)i;
int *q=(int *)j;
if(i >= 45)
return (p);
else
return (q);
}
Note in this case the use of register keyword is OK although it may have very limited effect. Also this would still warn you when you compile the code in some machine (especially 64 bit GCC).
Although strange, but this code have some sense: usually an integer that too close to zero is not a valid pointer.
So what this code does is: it returns i's value as a pointer if it's a valid pointer(value greater than 45), or return js value. The result in this case is 0x14 (remember we need to replace %d to %p, so the output is in hexadecimal).
EDIT
After look at your main function I believe what is wanted here would be
int check(register int i,register int j)
{
int p=i;
int q=j;
if(i >= 45)
return (p);
else
return (q);
}
But anyway this code can be simplified as
int check(register int i,register int j)
{
if(i >= 45)
return i;
else
return j;
}
or even
int check(register int i,register int j)
{
return i>=45 ? i : j;
}
in these cases the main function should be
int main()
{
int c;
c = check(10, 20);
printf("%d\n", c);
return 0;
}
Note since the data type of c is now int so the %p for printf is restored back to %d. The output is the same of the original code: 20.

OK now I see what you are asking.
If you have a function prototype declaration like this:
int *check(register int, register int);
As soon as the compiler sees this, it can enforce a rule that no code will attempt to obtain the address of the parameters. It is up to the compiler to consider a consistent way to generate code for function calls through out the program based on this fact. This may or may not be the same as
int *check(int, int);
Which performs the default treatment of parameters (but again the compiler will ensure it is consistent through out the program).
But consider the following:
int *check(auto int, auto int);
The compiler do not know weather the address of the parameter is going to be used or not unless it sees the actual implementation. So it cannot assume anything. The programmer obviously want some optimization, but the compiler do not have any further information to do so.
So it does not make sense to specify a parameter to be auto.
What if use auto for parameters of function definition? Again this makes little sense. The compiler can have a strategy that if there is no attempt to obtain the parameter address then treat it as register other use stack for it. But for parameters that do not use auto the rule would be the same. So it does not gives the compiler any further information.
Other storage classes are even makes no sense for parameters in function definition. It is not possible to pass a parameter through static data area or the heap (you can only pass pointers - which actually in the stack or registers).

Related

how to pass a condition as parameter to function in C?

I have created an array of function pointers to swap two variables.
pointer pointing to these functions namely: swap1, swap2. swap3 and swap4.
swap2 is swaping using pointer passed as arguments.
but while declaring the function pointer, only int and int are passed as arguments. after compiling this causes many warnings.
so do we have a better way of passing the argument, where we put condition in function call itself.
code is given below.
#include <stdio.h>
int swap1(int ,int );
int swap2(int* ,int* );
int swap3(int ,int );
int swap4(int, int);
int swap1(int a,int b)
{
int temp=a;
a=b;
b=temp;
printf("swapped with 3rd variable :%d, %d\n", a,b);
}
int swap2(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
printf("swapped with pointer :%d, %d\n", *a,*b);
}
int swap3(int a,int b)
{
a+=b;
b=a-b;
a-=b;
printf("swapped with 2 variable :%d, %d\n", a,b);
}
int swap4(int a,int b)
{
a=a^b;
b=a^b;
a=a^b;
printf("swapped with bitwise operation :%d, %d\n", a,b);
}
int main()
{
int ch;
int a=3;
int b=4;
printf("enter the option from 0 to 3\n");
scanf("%d",&ch);
int (*swap[4])(int, int) ={swap1,swap2,swap3,swap4};// function pointer
/*can we pass something like int(*swap[4]( condition statement for 'pointer to variable' or 'variable')*/
if (ch==1)// at '1' location, swap2 is called.
{
(*swap[ch])(&a,&b);//passing the addresses
}
else
{
(*swap[ch])(a,b);
}
return 0;
}
some warnings are as follows.
at line 36 in file '9e748221\script.c'
WARNING: found pointer to int where int is expected
at line 47 in file '9e748221\script.c'
WARNING: found pointer to int where int is expected
at line 47 in file '9e748221\script.c'
Well yes. There are a number of problems with your code, but I'll focus on the ones to which the warnings you presented pertain. You declare swap as an array of four pointers to functions that accept two int arguments and return an int:
int (*swap[4])(int, int)
Your function swap2() is not such a function, so a pointer to it is not of the correct type to be a member of the array. Your compiler might do you a better favor by rejecting the code altogether instead of merely emitting warnings.
Having entered a pointer to swap2() into the array anyway, over the compiler's warnings, how do you suppose the program could call that function correctly via the pointer? The type of the pointer requires function arguments to be ints; your compiler again performs the dubious service of accepting your code with only warnings instead of rejecting it.
Since the arguments in fact provided are the correct type, it might actually work on systems and under conditions where the representations of int and int * are compatible. That is no excuse, however, for writing such code.
Because pointers and ints are unchanged by the default argument promotions, one alternative would be to omit the prototype from your array declaration:
int (*swap[4])() = {swap1,swap2,swap3,swap4};
That says that each pointer points to a function that returns int and accepts a fixed but unspecified number of arguments of unspecified types. At the point of the call, the actual arguments will be subject to the default argument promotions, but that is not a problem in this case. This option does prevent the compiler from performing type checking on the arguments, but in fact you cannot do this correctly otherwise.
Your compiler might still warn about this, or could be induced to warn about it with the right options, but the resulting code nevertheless conforms and does the right thing, in the sense that it calls the pointed-to functions with the correct arguments.
To deal with the warnings first: You declare an array of functions which take int parameters. This means that swap2 is incompatible with the type of element for the array you put it in. This will generate a diagnostic.
Furthermore, when you call one of the functions in the array, the same array declaration tells the compiler that the parameters need to be ints not pointers to int. You get two diagnostics here, one for each parameter.
To fix the above all your functions need to have compatible prototypes with the element type of the array. Should it be int or int*? This brings us to the other problem.
C function arguments are always pass by value. This means that the argument is copied from the variable onto the stack (or into the argument register depending on the calling convention and argument count - for the rest of this post, I'll assume arguments are placed on the stack for simplicity's sake). If it's a literal, the literal value is put on the stack. If the values on the stack are changed by the callee no attempt is made by the caller, after the function returns, to put the new values back in the variables. The arguments are simply thrown away.
Therefore, in C, if you want to do the equivalent of call by reference, you need to pass pointers to the variables you use as arguments as per swap2. All your functions and the array should therefore use int*. Obviously, that makes one of swap1 and swap2 redundant.
The correct array definition is
int (*swap[4])(int*, int*) = {swap1, swap2, swap3, swap4};
and the definition of each function should be modified to take int* parameters. I'd resist the temptation to use int (*swap[4])() simply because it circumvents type safety. You could easily forget the & in front of an int argument when the called function is expecting a pointer which could be disastrous - the best case scenario when you do that is a seg fault.
The others have done great work explaining what the problems are. You should definitely read them first.
I wanted to actually show you a working solution for that sort of problem.
Consider the following (working) simple program :
// main.c
#include <stdio.h>
void swap1(int* aPtr, int* bPtr) {
printf("swap1 has been called.\n");
int tmp = *aPtr;
*aPtr = *bPtr;
*bPtr = tmp;
}
void swap2(int* aPtr, int* bPtr) {
printf("swap2 has been called.\n");
*aPtr += *bPtr;
*bPtr = *aPtr - *bPtr;
*aPtr -= *bPtr;
}
int main() {
int a = 1, b = 2;
printf("a is now %d, and b is %d\n\n", a, b);
// Declare and set the function table
void (*swapTbl[2])(int*, int*) = {&swap1, &swap2};
// Ask for a choice
int choice;
printf("Which swap algorithm to use? (specify '1' or '2')\n>>> ");
scanf("%d", &choice);
printf("\n");
// Swap a and b using the right function
swapTbl[choice - 1](&a, &b);
// Print the values of a and b
printf("a is now %d, and b is %d\n\n", a, b);
return 0;
}
First of, if we try to compile and execute it:
$ gcc main.c && ./a.out
a is now 1, and b is 2
Which swap algorithm to use? (specify '1' or '2')
>>> 2
swap2 has been called.
a is now 2, and b is 1
As myself and others mentioned in answers and in the comments, your functions should all have the same prototype. That means, they must take the same arguments and return the same type. I assumed you actually wanted to make a and b change, so I opted for int*, int* arguments. See #JeremyP 's answer for an explanation of why.

Casting Pointers to int in c

I have to learn it for my study. Is their any way to cast a pointer to integer. I have to give myEulerForward1 a pointer as a paramter and i always get this error message :
eulerZahl.c: In function ‘main’:
eulerZahl.c:38:35: warning: passing argument 1 of ‘myEulerForward1’ makes pointer from integer without a cast [-Wint-conversion]
double forward = myEulerForward1(k);
^
eulerZahl.c:16:8: note: expected ‘int *’ but argument is of type ‘int’
double myEulerForward1(int *n1){
^~~~~~~~~~~~~~~
Can someone help me with it?
#include <stdio.h>
#include <stdint.h>
double kFactorial(int k){
if(k <= 1){
return 1;
}
return k * kFactorial(k - 1);
}
double myEulerForward1(int *n1){
double n = 1;
double euler, nFact = 1;
for(int i = sizeof(&n1); i >= 0; i--){
nFact*= i;
euler = euler + (1.0/nFact);
}
return euler;
}
int main(){
int k = 4;
double factorial = kFactorial(k);
printf("The factorial of %d is: %lf ", k, factorial);
double forward = myEulerForward1(k);
printf("The Eulers Number: %lf", forward);
}
First i can see an error at sizeof(&n1);
Of course n1 is a pointeur. His Value is a RAM address. But for see his Deferenced value, you must use * before n1. & is used for get the adress of something. * is used for get the inside of a pointer.
Use : sizeof(*n1);
In Second, i see that you get a pointer in the prototype of myEulerForward1
double myEulerForward1(int *n1)
It's your compile error. He said that your function need a pointer (an adress) and that you put everything except that.
So when you call this function, you must put a pointer (a RAM adress).
And for do that, in the calling of the function, you must use & of course for get the adress of n1 and not his number value.
Use : double forward = myEulerForward1(&k);
Well, yes, it is possible to convert a pointer to an int, and vice versa.
However, you are making a serious mistake in asking that question. There are circumstances where converting an int to a pointer, or vice versa, makes sense. But, in your code, you would be using it as a blunt instrument to force the compiler to accept bad code.
Your compiler is complaining because you have passed an int to a function that expects an int *.
Forcing the issue, by converting that int to a pointer, will stop the compiler complaining, but then you'll (possibly) get some form of runtime error, since the function will receive an invalid pointer.
Your choices are
remove the * from double myEulerForward1(int *n1). This will mean, the function expects an int, so your code that passes an int will be correct.
Call the function as myEulerForward1(&k) which passes an address of k (which is not k converted to a pointer) as a pointer.
Looking at the body of myEulerForward1() there are other problems as well. You need to read up and better understand what sizeof does. Whether your function accepts an int or a pointer (int *) the logic of your function is faulty.

What is wrong with the following Code in C language?

I observed that in line int *x = malloc(sizeof(int)); this code is trying to convert a void* into a int* without using proper typecasting. So according to me answer should be option A. But in official GATE-2017 exam answer key, answer is given D. So am i wrong ? how ?
#include<stdio.h>
#include<iostream.h>
#include<conio.h>
#include<stdlib.h>
int *assignval(int *x, int val){
*x = val;
return x;
}
void main(){
clrscr();
int *x = malloc(sizeof(int));
if(NULL==x) return;
x = assignval(x,0);
if(x){
x = (int *)malloc(sizeof(int));
if(NULL==x) return;
x = assignval(x,10);
}
printf("%d\n",*x);
free(x);
getch();
}
(A) compiler error as the return of malloc is not typecast
appropriately.
(B) compiler error because the comparison should be made as x==NULL
and not as shown.
(C) compiles successfully but execution may result in dangling
pointer.
(D) compiles successfully but execution may result in memory leak.
In my opinion option D is only correct when int *x = (int *)malloc(sizeof(int)); is used.
There's no right answer among the choices offered.
The immediately obvious problems with the code, under assumption that the code is supposed to be written in standard C:
Standard library does not have <conio.h> header or <iostream.h> header.
void main() is illegal. Should be int main(). Even better int main(void)
clrscr(), getch() - standard library knows no such functions.
The second malloc leaks memory allocated by the first one (assuming the first one succeeds).
Result of second malloc is explicitly cast - bad and unnecessary practice.
The statement :
int *x = malloc(sizeof(int));
will not lead to compile error, as it declares x as a pointer to int and initializes it right afterwards. It did not have type void beforehand.
The statement :
x = (int *)malloc(sizeof(int));
causes a possible memory leak, as it reallocates the memory which is already allocated for x.
NOTE : However none of this answers is completely correct. This code will not compile for various reasons.
If this is your code, change :
void main()
to :
int main(void)
and also see why you should not cast the result of malloc.
Apart from that, clrscr(), getch(), <conio.h> and <iostream.h> are not recognized by standard library.
I observed that in line int *x = malloc(sizeof(int)); this code is trying to convert a void* into a int* without using proper typecasting.
There's more than a little debate about whether or not to cast malloc, but it's a stylistic thing. void * is safely promoted to any other pointer.
ISO C 6.3.2.3 says...
A pointer to void may be converted to or from a pointer to any incomplete or object type. A pointer to any incomplete or object type may be converted to a pointer to void and back again; the result shall compare equal to the original pointer.
Whatever you choose, pick one and stick with it.
The memory leak is here:
int *x = malloc(sizeof(int));
if(NULL==x) return;
x = assignval(x,0);
if(x){
// Memory leak
x = (int *)malloc(sizeof(int));
The first malloc points x at allocated memory. The second malloc can only happen if the first succeeded (if x is true). The pointer to the memory allocated by the first malloc is lost.
Using a new variable would fix the leak, keeping in mind that the code is nonsense.
int *x = malloc(sizeof(int));
if(NULL==x) return;
x = assignval(x,0);
if(x){
int *y = malloc(sizeof(int));
if(NULL==y) return;
y = assignval(y,10);
free(y);
}
As a side note, void main() is technically not a violation of the ISO C standard, it is "some other implementation-defined manner".
5.1.2.2.1 says:
The function called at program startup is named main. The implementation declares no prototype for this function. It shall be defined with a return type of int and with no parameters:
int main(void) { /* ... */ }
or with two parameters (referred to here as argc and argv, though any names may be used, as they are local to the function in which they are declared):
int main(int argc, char argv[]) { / ... */ }
or equivalent;) or in some other implementation-defined manner.
I'm guessing you're using a Windows compiler, that would be the "some other implementation". clang considers it an error.
test.c:8:1: error: 'main' must return 'int'
void main(){
^~~~
int
1 error generated.
you should never forget that a void * pointer can be assigned to all type of pointers. in IDEs like visual studio, you get a compile error if you do not perform casting while assigning a void * to <>. for example:
float *ptr = malloc(sizeof(float));//compile error in visual studio.
but if you compile it with GCC without typecasting, you won't get a compile error.

The compiler gives no warning on returning local pointer

I am using code blocks with GCC compiler. In the code below, compiler gives warning while returning local reference but no warning on returning local pointer though both are same thing. Why ?
I understand these variables are local and will be destroyed as soon as control returns from the function. De-referencing these would result in undefined behavior.
int *check(int j)
{
int *q;
q= &j;
return q; // No warning
//return &j; // Warning
}
First, because warnings are optional.
Second, this code
int *q
...
return q;
doesn't return a the address of a local variable directly. You wrote the explicit code that made the pointer point to an address that becomes invalid when the function returns. No compiler can be expected to save you from that.
Andrew I would have to disagree.
According to gcc documentation
-Wno-return-local-addr
Do not warn about returning a pointer (or in C++, a reference) to a variable that goes out of scope after the function returns.
Edit: I redact my earlier claim. Turns out GCC does disappoint me. Apparently that error only works if you directly return something that will be cleared from the stack. If you store it in a temporary variable GCC does not check that even though it has more then enough information to do so just my checking if the pointer leads to some address between %EBP and %ESP
Here is some code I made to test it real quick to confirm that GCC doesn't check. If you run this with -Wall it produces no error however if you return &val it will produce two warnings (one for the return one for j not being used). I feel like GCC should recursively check that my returned pointer stays in scope rather then just checking the immediate value.
#include <stdio.h>
#include <stdlib.h>
int * myFunc(int val){
int *j;
j=&val;
return j; //Should not work val goes out of scope
}
int someFuncToClearMyStack(int a, int b, int c){
int d;
int e;
d=a+b+c;
e=c-b-a;
d=d-e;
return d;
}
int main(){
int *i;
int j;
i=myFunc(10);
printf("%i\n",*i);
j=someFuncToClearMyStack(3,4,5);
printf("%i %i",*i,j);
return 0;
}

C conflicting type bug

When I try to compile this I'm being told by gcc that I have conflicting types for pack_cui(C).
I don't see how I could be getting conflicting types as I know I'm passing in a char*. I'm new to C so I'm sure I'm missing something obvious.
int main(){
char* C = malloc(sizeof(char) * 4);
C[0] = 1;
C[1] = 2;
C[2] = -1;
C[3] = 4;
pack_cui(C);
return 0;
}
unsigned int pack_cui(char* C){
unsigned int new_int = 0;
unsigned int i;
for(i = 0; i < 4; i++){
new_int = new_int | (unsigned int)(signed int)C[i];
if(i != 3) new_int = new_int << 8;
}
return new_int;
}
The error I received was
hw12.c:17:14: error: conflicting types for ‘pack_cui’
unsigned int pack_cui(char* C){
^
hw12.c:13:5: note: previous implicit declaration of ‘pack_cui’ was here
pack_cui(C);
Add a prototype for pack_cui before main:
unsigned int pack_cui(char* C);
Otherwise, when the compiler sees the call to pack_cui, it has to guess the type, and in this case it guesses wrong.
When you call an undeclared function, the C89 standard mandates an implicit declaration. This declaration would be:
int pack_cui();
The () is not the same as (void), it indicates that the function takes an unspecified number of arguments, whereas (void) means zero. This is left over from pre-ISO/ANSI C, back in the K&R days.
You don't want that, because that is the wrong declaration. Create your own declaration at the top, above main():
unsigned pack_cui(char *);
Move the definition of pack_cui from below the main function, to above the main function. Or set up and include a header file that declares pack_cui.
Also, once this is done, recompile with warnings enabled, so that you catch the other issue with your code:
$ gcc -Wall foo.c
You should include stdlib.h, at least.
When you call a C function, whether it's one of your own or one declared by the standard library, you must have a visible declaration of that function so the compiler knows how to generate the code to call it. That declaration should be a prototype, i.e., a declaration that specifies the types of the function's parameters. A function definition (with the { ... } containing the code that implements the function) provide a declaration.
In your example, no declaration of pack_cui is visible at the point of the call; it's not defined until later.
You can fix this by moving the definition of pack_cui above the definition of main, or by adding a "forward declaration" and leaving the definitions where they are.
The latter would look like this:
unsigned int pack_cui(char* C); /* a declaration, not a definition */
int main(void) { /* definition of main */
/* ... */
}
unsigned int pack_cui(char* C) { /* definition of pack_cui */
/* ... */
}
Either approach is acceptable.
For much the same reason, you need to provide a declaration for the malloc function. You should do this by adding
#include <stdlib.h>
to the top of your source file.

Resources