GCC shows line numbers for the .c file, which in my case is a macro that is defined using other macros, which are defined using even more macros, etc. Is there a way to have GCC give the line numbers for the preprocessed .i file instead?
bla.c
#include <stdlib.h>
#include <stdio.h>
#define PRINT(a) printf("%d\n", (a));
int main()
{
double a = 2.5;
PRINT(a);
return 0;
}
It will print the warning for the line containing PRINT(a) (line 10), but I want it to print the line containing printf("%d\n", (a));; from the preprocessed file (line 1837)
preprocessed file:
<other code above>
int main()
{
double a = 2.5;
printf("%d\n", (a));;
return 0;
}
Use the options -no-integrated-cpp -P to get:
/tmp/ccQ2ECah.i: In function 'main':
/tmp/ccQ2ECah.i:729:14: warning: format '%d' expects argument of type 'int', but argument 2 has type 'double' [-Wformat=]
729 | printf("%d\n", (a));;
| ~^ ~~~
| | |
| int double
| %f
The -no-integrated-cpp option causes the preprocessor and compiler to run as truly separate passes, where the only communication between them is the preprocessor output.
In this mode, the preprocessor would normally include #line directives in its output to identify source line numbers from the original file. The -P option suppresses them. Then the compiler pass has no information about the original file's line numbers, and can only print the line numbers of the preprocessor output.
Related
I'm trying to build a project 8051 in Keil IDE.
I have a definition to print information for purposes debug program as following:
#define LOGI(fmt, ...) printf("[I] %s:%u: "fmt, __FILE__, __LINE__, ##__VA_ARGS__)
But there are errors:
log.h(18): error C301: identifier expected
log.h(18): error C301: identifier expected
log.h(18): error C304: bad macro parameter list
Please help me fix this code, thank you.
According to the documentation, Keil C51 is based on C90. So it does not support __VA_ARGS__ that is a C99 addition.
However, you can work around this for example by this trick. Use a parenthesized argument.
#define LOGI(args) \
do { \
printf("[I] %s:%u: ", __FILE__, __LINE__); \
printf args; \
} while (0)
void f(void) {
LOGI(("address of f() = %p\n", f));
}
Another possible solution is to provide an own function with a variable number of arguments, see the example in the documentation. This is a cleaner way because you can use this function without a "hick-up" when reading the source code because of the double parentheses. But be aware that these arguments are not placed in registers, and more memory on stack and in code is used.
#include <stdio.h>
#include <stdarg.h>
void logi(const char* filename, int line, char *fmt, ...) {
va_list arg_ptr;
va_start(arg_ptr, fmt);
printf("[I] %s:%u: ", filename, line);
vprintf(fmt, arg_ptr);
va_end(arg_ptr);
}
void f(void) {
logi(__FILE__, __LINE__, "Hello %u %u", 1 , 2);
}
Note: You might want to switch to another compiler, which supports some newer standard than a 30 years old one.
I am getting the following error
rudimentary_calc.c: In function ‘main’:
rudimentary_calc.c:9:6: error: conflicting types for ‘getline’
9 | int getline(char line[], int max) ;
| ^~~~~~~
In file included from rudimentary_calc.c:1:
/usr/include/stdio.h:616:18: note: previous declaration of ‘getline’ was here
616 | extern __ssize_t getline (char **__restrict __lineptr,
| ^~~~~~~
when I ran the following code
#include <stdio.h>
#define maxline 100
int main()
{
double sum, atof(char[]);
char line[maxline];
int getline(char line[], int max) ;
sum = 0;
while (getline(line, maxline) > 0)
printf("\t %g \n", sum += atof(line));
return 0;
}
What am I doing wrong? I am very new to C, so I don't know what went wrong.
Generally, you should not have to declare "built-in" functions as long as you #include the appropriate header files (in this case stdio.h). The compiler is complaining that your declaration is not exactly the same as the one in stdio.h.
The venerable K&R book defines a function named getline. The GNU C library also defines a non-standard function named getline. It is not compatible with the function defined in K&R. It is declared in the standard <stdio.h> header. So there is a name conflict (something that every C programmer has do deal with).
You can instruct GCC to ignore non-standard names found in standard headers. You need to supply a compilation flag such as -std=c99 or -std=c11 or any other std=c<year> flag that yout compiler supports.
Live demo
Always use one of these flags, plus at least -Wall, to compile any C code, including code from K&R. You may encounter some compiler warnings or even errors. This is good. Thy will tell you that there are some code constructs that were good in the days of K&R, but are considered problematic now. You want to know about those. The book is rather old and the best practices and the C language itself have evolved since.
I'm trying to connect simple flex and bison code that would just recognize a character for now. Yet I'm facing this error. I've read through a lot of answers to figure out what is wrong but am lost. Any help would be highly appreciated as I'm just starting out to explore this and could not find a lot of resources for it.
This is my .l file
%{
#include <stdlib.h>
#include <stdio.h>
#include "MiniJSC.tab.h"
void yyerror (char *s);
int yylex();
%}
%%
[0-9]+ { yylval.num = atoi(yytext); return T_INT_VAL; }
%%
int yywrap (void) {return 1;}
my .y file
%{
void yyerror (char *s);
int yylex();
#include <stdio.h> /* C declarations used in actions */
#include <stdlib.h>
%}
%union {int num; char id;} /* Yacc definitions */
%start line
%token print
%token T_INT_VAL
%type <num> line
%type <num> term
%type <num> T_INT_VAL
%%
/* descriptions of expected inputs corresponding actions (in C) */
line : print term ';' {printf("Printing %d\n", $2);}
;
term : T_INT_VAL {$$ = $1;}
;
%% /* C code */
void yyerror (char *s) {
fprintf (stderr, "%s\n", s);
}
int main (void) {
return yyparse ( );
}
The compilation and output:
$ bison MiniJSC.y -d
$ lex MiniJSC.l
$ gcc lex.yy.c MiniJSC.tab.c
$ ./a.out
10
syntax error
$
line : print term ';'
According to this, a valid line contains a print token followed by a term. Since a term must be a T_INT_VAL token, that means a valid line is a print token followed by a T_INT_VAL token.
Your input consists only of a T_INT_VAL token, so it is not a valid line and that's why you get a syntax error.
Also note that your lexer never produces a print token, so even if you entered print 10 as the input, it'd be an error since the lexer isn't going to recognize print as a token. So you should add a pattern for that as well.
You should also rename print to match your naming convention for tokens (i.e. ALL_CAPS).
Is there a way to make GCC display the value of some preprocessed value during preprocessing? In particular, if I run the equivalent of:
gcc input.c -E >/dev/null
Is there a way to obtain the actual value of an expanded macro? Consider this example:
#if defined(A)
#define B bar
#else
#define B foo
#endif
#define XSTR(x) STR(x)
#define STR(x) #x
int main() {
#pragma message "B is " XSTR(B)
#error DIE
B a = 2;
return 0;
}
I would like to find out that B is foo in this case.
In my actual setup, I do not have access to the entirely preprocessed file, and I cannot remove the -E flag.
Rationale: I have a complex file setup with lots of syntax errors due to incorrectly defined macros, and the fastest way to debug it would be to use this #pragma/#error combination to find out the actual value, stop compilation, manually fix it, and run GCC again to find out where the next error will occur.
I am using Exuberant Ctags v5.8 and the C source sample that I would like to generate tags file from is as below, thanks!
#define PACK(x) __packed x
typedef PACK(struct) {
int a;
int b;
int c;
} my_struct;
PACK(void *) my_func(PACK(void *) var1, int var2)
{
*var1 = var2;
return var1;
}
And this is the contents of generated tag file:
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert#users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //
PACK test.c /^#define PACK(/;" d file:
PACK test.c /^typedef PACK(struct) {$/;" f
while my expected contents of tag file should be as following:
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
!_TAG_PROGRAM_AUTHOR Darren Hiebert /dhiebert#users.sourceforge.net/
!_TAG_PROGRAM_NAME Exuberant Ctags //
!_TAG_PROGRAM_URL http://ctags.sourceforge.net /official site/
!_TAG_PROGRAM_VERSION 5.8 //
a test.c /^ int a;$/;" m struct:__anon1 file:
b test.c /^ int b;$/;" m struct:__anon1 file:
c test.c /^ int c;$/;" m struct:__anon1 file:
my_func test.c /^void * my_func(void * var1, int var2)$/;" f
my_struct test.c /^} my_struct;$/;" t typeref:struct:__anon1 file:
How can I get the latter tag file from original C source file? Thanks!
This cannot be done directly without preprocessing the files yourself (e.g. with awk, as I commented above) and having Exuberant Ctags operate on the preprocessed version.
Exuberant Ctags uses the -I command line option to handle defines. It allows you to ignore preprocessor defines (e.g -I PACK), do substitution of defines (e.g. -I PACK=FOO), and it allows you to ignore the identifier and its argument list (e.g. -I PACK+), but none of these options handle replacing the macro with one of its arguments.
You might consider requesting this as a new feature, but it doesn't appear to be actively developed anymore. The last revision was in July 2009.