I was reading "Compiler Design in C" book. In the basics section I found a c snippet for lexer something like this -
static int Lookahead = -1;
int match(token)
int token;
{
if(Lookahead == -1)
Lookahead = lex();
return token == Lookahead;
}
void advance(){
Lookahead = lex();
}
I got confuse about how this match function get compiled on gnu gcc. So I wrote a function that looks like
int a(token)
int token;
{
printf("Value of token is %d", token);
}
int main()
{
printf("Hello world!\n");
a(1);
return 0;
}
And I am getting following output-
Hello world!
Value of token is 1
But I dont getting the reason behind that function declaration. What the benefit of declaring function this way? And how the value of token being 1? Why its not a compile error? Is it some kind of function declaration in C?
Thanks for checking my question. Any kind of help will be great.
Its an old and deprecated K&R style of function declaration.
int match(token)
int token;
{
// Function body
}
is equivalent to
int match(int token)
{
// Function body
}
except that in former, compiler would not check that the function is called with the right number of arguments nor will it check the types of arguments. It rely on default argument promotions.
C89 and C99 support this style too.
This is the original way that C functions used to be declared when Kernighan and Ritchie first developed the C programming language. It is referred to as 'K&R C'
C went through a standardisation process and this form of function declaration was changed to the one that you are used to.
On the page http://en.wikipedia.org/wiki/The_C_Programming_Language the first edition of the book would have had the old style function declarations, I think it was dropped in the second edition.
Function definitions in the original K&R C were simpler. In your example, the type declaration for function parameter token is actually redundant. The code could be simplified this way:
static int Lookahead = -1;
int match(token) {
if (Lookahead == -1)
Lookahead = lex();
return token == Lookahead;
}
void advance(){
Lookahead = lex();
}
Indeed the function return type and variable types also defaulted to int, void was not yet invented, the return statement was optional... leading to further simplification:
static Lookahead=-1;
match(token){
if(Lookahead==-1) Lookahead=lex();
return token==Lookahead;
}
advance(){Lookahead=lex();}
Such primitive style was more compact, but was quite error prone and is no longer supported by modern conforming compilers. The function definition syntax in your example is still supported, but considered obsolete and likely to disappear at some point.
Related
While making a function atof, I splitted the entire work into two separate translational units:
m.c
#include<stdio.h>
extern fun(char[]); //return type not mentioned on purpose
int main()
{
printf("%d\n",fun("+123.980")); //%f would also display 0.000000
return 0;
}
n.c
#include<ctype.h>
float fun(char c[])
{
float val=0, pow=1;
int i;
int sign;
for(i=0;isspace(c[i]);i++); //SKIPPING WHITESPACE IF ANY
if(c[i]=='+')
sign = 1;
if(c[i]=='-')
sign =-1;
++i;
for(;c[i]!='.';i++)
val = val*10 + (c[i]-'0');
++i;
while(isdigit(c[i]))
{
val = val*10 + (c[i]-'0');
pow=pow*10;
++i;
}
return sign*val/pow;
}
The warning says that the type of function will default to int in this case since every variable/function type at global space without any return type mentioned explicitly defaults to int.
I was expecting the output to be int version of +123.980 i.e 123 only.
But instead it shows 0 (otherwise function works fine). Why?
Implicit int and implicit function declarations are removed from the C language. They are no more. The program is ill-formed. If your compiler accepts it, then you are dealing with a vendor extension — or a compiler for an outdated version of C.
Before these things were removed, the program had undefined behaviour. All editions of the standard require that all declarations of an entity in a program must be compatible, regardless of whether anything in them is implicit or not. Violations of this rule lead to undefined behaviour, with no diagnostic required.
Lets say I am maintaining an array of function structures in which I store API information.
This is definition of function structure:
typedef struct function {
void (*func)(long, ...);
char* name;
int argc;
char *argv[];
} function;
function api_list[N]
I would maintain a list of such structures.
Now given any function, I want to write a function Register(api_list, fp)
which adds one such structure initialized with details of function fp.
int fp(int a, int b) {
return a+b;
}
Register(api_list, fp);
How to do it in C?
I believe you will need to either parse the C function declarations yourself or find some other code to do it. I looked around a bit and there's code for this in the Ruby FFI, PerlXS and other script binding generators like SWIG. I also saw the XML plugin to GCC which generates XML describing the program.
If you look up C's BNF or EBNF definitions and know a bit of parsing theory, figuring out C functions is not hard. C++ is a whole other ball o' wax.
Note: I think I misunderstood. The following is for calling C functions with unknown number and types of arguments. Not for finding out what the function signature already looks like.
Look at the FFI (Foreign Function Interface) library which can be found at Sourceware:
https://sourceware.org/libffi/
This is packaged with many Linux systems already because it is heavily used by interpreted languages that need to call C functions.
Now given any function, I want to write a function Register(api_list, fp) which adds one such structure initialized with details of function fp.
There is no way to do this in Standard C. The main reason is you need keep track of original definition of an function to call it via such structure. You actually could store every function pointer as struct member:
void (*func)()
that is fine, but any attempt to call such function when type is not compatible (both parameters and return type are not the same) with original definition will invoke undefined behaviour. This means, that you would need to cast it properly for every call:
((int (*)(int, int)) api_list[0])(1, 2);
You may use GCC extensions typeof, but this method requires writing function's name (here fp) explicitely:
int result = ( (typeof(fp)*) api_list[0].func)(1, 2);
Even if you have stored somehow character string "fp" inside name member, there is no way to "connect" it with typeof, since it does not take string literals (well it takes, but not in the way you want) and in general there is no way to have it "destringized" as fp token.
Here is an illustration of above concepts:
#include <stdio.h>
typedef void (*GENERIC_FUNC_PTR)();
typedef struct function
{
GENERIC_FUNC_PTR func;
} function;
void Register(function *api_list, GENERIC_FUNC_PTR func)
{
api_list->func = func;
}
int add(int a, int b)
{
return a + b;
}
void print_message(void)
{
printf("%s\n", __func__);
}
int main(void)
{
function api_list[10];
Register(api_list, (GENERIC_FUNC_PTR) add);
Register(api_list + 1, (GENERIC_FUNC_PTR) print_message);
printf("%d\n", ( (typeof(add)*) api_list[0].func)(1, 2));
( (typeof(print_message)*) api_list[1].func)();
return 0;
}
This question already has answers here:
Why does a function with no parameters (compared to the actual function definition) compile?
(11 answers)
Closed 9 years ago.
The book that i am currently reading states that when you declare a function in c that accepts no arguments, but you do not use the keyword void "the function call can pass any
arguments it wants". so i attempted this.
int number();
int main(void)
{
int x =1;
printf("%d",number(x));
}
int number()
{
return x;
}
but it did not compile??? how does this work?
This is an obsolescent feature1 from before C was standardized, decades ago.
Never use it.
In ancient C, a decade before you were born, you could declare a function with no parameters. When you called it, the compiler would promote the arguments to default types and pass them to the function. Essentially, the compiler figured out the parameter declarations from the arguments in the call.
The function should still be defined with parameters, and they should match the way the function is called.
1 “Feature” is the wrong word. It was the way things were done at the time, since better ways were not yet widely developed. In a new programming language, this characteristic would be considered a deficiency.
In support of Eric Postpischil's answer I would like to quote from the C11 standard (6.11 Future language directions)
6.11.6 Function declarators
The use of function declarators with empty parentheses (not
prototype-format parameter type declarators) is an obsolescent
feature.
and
6.11.7 Function definitions
The use of function definitions with separate parameter identifier and
declaration lists (not prototype-format parameter type and identifier
declarators) is an obsolescent feature.
Emphasis is mine :)
The issue here is that your function number has no knowledge of x.
That is, when you have the function number return x, it doesn't have any x in scope to return, and so this is a compile error. If, instead, you wrote:
int number() {
return 5;
}
it would compile fine.
Well, if you want pass something to it without limit , you may need a a variable argument list.Here is an example:
#include <stdio.h>
#include <stdarg.h>
int number(int , ... );
int main(void)
{
int x =1;
printf("%d",number(1,x));
}
int number(int n, ... )
{
va_list ap;
va_start(ap,n);
int x = va_arg(ap,int);
va_end(ap);
return x;
}
Or , if you just want to pass x but not use it.
#include <stdio.h>
int number();
int main(void)
{
int x =1;
printf("%d",number(x));
}
int number()
{
int x = 1;
return x;
}
It can compile and work. When you declare int number (); in C , you mean this function can be given unspecial type . however , you can't use it.
Well I edited the whole answer after finding the answer.
What you want to do is number(void) not main(void). That's what you wanted and that will print any variable as a integer. If you pass the char "F" int number(void) will return the number 70, the int form of "F". In code:
int number(void e);
void main(){
char C = 'F';
printf("%d",number(C));
};
int number(void e){
return e;
};
Note:
You must always pass an argument if you want a variable that's out of scope.
I've been trying to figure out what's wrong with this code without success for a while:
#include"ec.h"
#include"pantalla.h"
#include"so.h"
#define NPROC 20
WORD flags;
void (*rsi_ck)();
char idproces = 'a';
tPCB *pRUN, *pRDY;
tPCB pcbs[NPROC];
char arterisc[]="|/-\\";
void crearProces (tcpb *pcb,PTR funcio)
{
pcb->IdProces = (int) idproces;
a=a+1;
pcb->Estat = RDY;
pcb->Flags = flags;
pcb->CS = Segment(funcio);
pcb->IP = Desplacament(funcio);
pcb->SS_SP =(long)(&(pcb->Pila[MIDA_PILA-12]));
pcb->Pila[MIDA_PILA-11]=Segment(&pRUN);
pcb->Pila[MIDA_PILA-1]=512;
pcb->Pila[MIDA_PILA-2]=pcb->CS;
pcb->Pila[MIDA_PILA-3]=pcb->IP;
}
//more lines below
It gives me a compilation error, ", expected" on line 16, where the function "CrearProces" is defined. I've tried to move the definition of the function to any other line and the error just "follows" it.
Thanks in advance.
Edit: tPCB is defined as follows:
typedef struct
{
LONG IdProces;
WORD Estat;
LONG SS_SP;
WORD Quantum;
WORD Prioritat;
WORD Flags;
WORD CS;
WORD IP;
WORD Pila[MIDA_PILA];
} tPCB;
What's a "tcpb" in void crearProces (tcpb *pcb,PTR funcio)? Should it be a tPCB?
For historical reasons C language supports two styles of function declarations (and definitions).
The "new" prototype-based style
void foo(int a, short b, double c)
{
...
And the "old" K&R style
void foo(a, b, c)
int a;
short b;
double c;
{
...
When the compiler sees that the first identifier in () is a known type name, it assumes that the function is defined with prototype. When the compiler sees that the first identifier in () is not a known type name, it assumes that the function is defined in old K&R style. In the latter case each identifier must be separated from the next one by ,.
In your case the function definition has tcpb as the first identifier in (). Apparently there's no such type in your program, which makes the compiler to assume that this is not a type name but rather a parameter name in a K&R style definition. As such it must be followed by a ,.
This is obviously not your intent.
So, what is tcpb? Why are you using it as a type name when there's no such type in your program?
P.S. Different compilers can use different approaches to recognize invalid code. For that reason, they can detect the same error differently and issue different diagnostic messages. Apparently your specific compiler is using the logic I described above. Hence the error message about a comma. Another compiler might report the same error differently.
How do I approach a function echo_tpl that can take 1 parameter of type int or string ,and print it out?
C doesn't have templates. I think the best you could do is to use an union or to have the functions have different names. The latter way of having different names is the quasi-standard method of doing it (for instance fabs fabsf fabsl, also heavily used by OpenGL which also accounts for the fact C can't overload functions)
void echo_tpl_s(char const *string) { /* ... */ }
void echo_tpl_i(int number) { /* ... */ }
int main(void) {
echo_tpl_s("Hello world");
echo_tpl_i(42);
}
If there is a lot of common code, you may decide to factor it out in separate functions
void echo_tpl_s(char const *string) {
prepare_output_device();
printf("%s", string);
unprepare_output_device();
}
void echo_tpl_i(int number) {
prepare_output_device();
printf("%d", number);
unprepare_output_device();
}
Or you can take the union way, which will have the function names be equal but instead blow up the parameter type with meta informations.
enum Type {
Number,
String
};
struct Value {
enum Type type;
union {
int number;
char const *string;
} u;
};
void echo_tpl(struct Value value) {
switch(value.type) {
case Number: printf("%d", value.u.number); break;
case String: printf("%s", value.u.string); break;
}
}
int main(void) {
echo_tpl((struct Value) {
.type = String,
.u.string = "Hello world"
});
}
The union way is particular well-suited if you want to store the value somewhere and then execute the print function without caring what value type you pass to it. In C89 you would need to create the value separately since it doesn't have compound literals
int main(void) {
struct Value value;
value.type = String;
value.u.string = "Hello world";
echo_tpl(value);
}
It's a good idea to create functions for that, though
struct Value stringval(char const *string) {
struct Value value;
value.type = String;
value.u.string = string;
return value;
}
struct Value numberval(int number) {
struct Value value;
value.type = Number;
value.u.number = number;
return value;
}
int main(void) {
echo_tpl(stringval("Hello world!"));
}
Some compilers may provide extensions for writing such things. For instance Clang provides function overloading in C.
void echo_tpl(int value) __attribute__((overloadable)) {
printf("%d", value);
}
void echo_tpl(char const *value) __attribute__((overloadable)) {
printf("%s", value);
}
This solves the call-side of the function not to depend on the type. On the definition side, you still have to write the code twice. That's mainly because (as another answer explains) C doesn't have type-generic output functions. Of course if you use this feature, your code becomes nonportable.
The traditional way to translate templates to C is using the preprocessor. I'd do it something like this:
// this creates each template "instance"
#define ECHO_TPL_IMPLEMENT(t) void echo_tpl_##t(t param){\
/* this is where you write your function that uses param */ \
}
// this calls the specific template instance
#define ECHO_TPL(t, val) echo_tpl_##t(val)
// as i wrote it, the function only accepts a 1 word parameter type
// so for simplicity, i'm defining char* to be string
typedef char *string;
// i implement the function for the types int and string
ECHO_TPL_IMPLEMENT(int) // creates echo_tpl_int
ECHO_TPL_IMPLEMENT(string) // creates echo_tpl_string
main()
{
// then i just call them and let the preprocessor handle it
ECHO_TPL(string, "meep"); // will call echo_tpl_string
ECHO_TPL(int, 10); // will call echo_tpl_int
}
This is how the original C++ compilers handled templates, only they had (and still do to this day) more complex type mangling rules, where I just assumed types are 1 word and if they aren't, you'll have to typedef them.
edit: Note that I left the function empty. This is indeed how you write "templated functions" in C, but I cant really write the parameter like you asked because C doesn't have a type-independent file writing api. printf and write require information about the actual type (through the %d or %s and through the length in bytes of what to write respectively), and we don't have that.
Also note that this applies to C++ too. You can't use the C api to write to a file from a template either, you can only really use cout (or the boost format alternative or something similar). You'll have to think what you want to do with the actual function.
Late, but worth adding to this that as of the C11 standard, C now has some very limited support for overloading by using _Generic expressions, that select the right result expression at compile-time based on the type of an input. Nothing like templates but they can answer this old question like this:
#define echo_tpl(X) _Generic((X), int: echo_tpl_i, \
char *: echo_tpl_s)(X)
void echo_tpl_s(char const *string) { /* ... */ }
void echo_tpl_i(int number) { /* ... */ }
int main(void) {
echo_tpl("Hello world");
echo_tpl(42);
}
You still have to define the function implementations using separate names as you would in C99, but you can define a macro with the C++-ish name that inserts a _Generic expression at every point of use, in order to choose the right version for that call site, without making the function user think about the argument type.
It seemingly takes forever for C standards to be fully adopted and I have no idea which compilers implement this feature, but it will become widespread sooner if more people go forth and use it!
template <typename T>
void echo_tpl(const T& t) { std::cout << t; }
EDIT: I didn't spot the c tag. The above answer only works with C++.