Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there a C compiler that fails to compile this?

Tags:

I was hanging out in my profiler for a while trying to figure out how to speed up a common log parser which was bottlenecked around the date parsing, and I tried various algorithms to speed things up.

The thing I tried that was fastest for me was also by far the most readable, but potentially non-standard C.

This worked quite well in GCC, icc, and my really old and picky SGI compiler. As it's a quite readable optimization, where doesn't it do what I want?

static int parseMonth(const char *input) {     int rv=-1;     int inputInt=0;     int i=0;      for(i=0; i<4 && input[i]; i++) {         inputInt = (inputInt << 8) | input[i];     }      switch(inputInt) {         case 'Jan/': rv=0; break;         case 'Feb/': rv=1; break;         case 'Mar/': rv=2; break;         case 'Apr/': rv=3; break;         case 'May/': rv=4; break;         case 'Jun/': rv=5; break;         case 'Jul/': rv=6; break;         case 'Aug/': rv=7; break;         case 'Sep/': rv=8; break;         case 'Oct/': rv=9; break;         case 'Nov/': rv=10; break;         case 'Dec/': rv=11; break;     }     return rv; } 
like image 338
Dustin Avatar asked Nov 29 '08 23:11

Dustin


People also ask

Why C compiler is not working?

This usually happens when you don't have C/GCC compiler installed on your server. All you got to do is to install gcc to resolve this. If using CentOS 8 then you can use the DNF command. Once installed, you can verify as below.

What is compile error in C?

Compilation error refers to a state when a compiler fails to compile a piece of computer program source code, either due to errors in the code, or, more unusually, due to errors in the compiler itself. A compilation error message often helps programmers debugging the source code.

Will C compiler always compile C++ code?

If the C++ compiler provides its own versions of the C headers, the versions of those headers used by the C compiler must be compatible. Oracle Developer Studio C and C++ compilers use compatible headers, and use the same C runtime library. They are fully compatible.

Does C code need to be compiled?

C is a mid-level language and it needs a compiler to convert it into an executable code so that the program can be run on our machine.


2 Answers

Solaris 10 - SPARC - SUN Compiler.

Test code:

#include <stdio.h>  static int parseMonth(const char *input) {     int rv=-1;     int inputInt=0;     int i=0;      for(i=0; i<4 && input[i]; i++) {         inputInt = (inputInt << 8) | input[i];     }      switch(inputInt) {         case 'Jan/': rv=0; break;         case 'Feb/': rv=1; break;         case 'Mar/': rv=2; break;         case 'Apr/': rv=3; break;         case 'May/': rv=4; break;         case 'Jun/': rv=5; break;         case 'Jul/': rv=6; break;         case 'Aug/': rv=7; break;         case 'Sep/': rv=8; break;         case 'Oct/': rv=9; break;         case 'Nov/': rv=10; break;         case 'Dec/': rv=11; break;     }      return rv; }  static const struct {     char *data;     int   result; } test_case[] = {     { "Jan/", 0 },     { "Feb/", 1 },     { "Mar/", 2 },     { "Apr/", 3 },     { "May/", 4 },     { "Jun/", 5 },     { "Jul/", 6 },     { "Aug/", 7 },     { "Sep/", 8 },     { "Oct/", 9 },     { "Nov/", 10 },     { "Dec/", 11 },     { "aJ/n", -1 }, };  #define DIM(x) (sizeof(x)/sizeof(*(x)))  int main(void) {     size_t i;     int    result;      for (i = 0; i < DIM(test_case); i++)     {         result = parseMonth(test_case[i].data);         if (result != test_case[i].result)             printf("!! FAIL !! %s (got %d, wanted %d)\n",                    test_case[i].data, result, test_case[i].result);     }     return(0); } 

Results (GCC 3.4.2 and Sun):

$ gcc -O xx.c -o xx xx.c:14:14: warning: multi-character character constant xx.c:15:14: warning: multi-character character constant xx.c:16:14: warning: multi-character character constant xx.c:17:14: warning: multi-character character constant xx.c:18:14: warning: multi-character character constant xx.c:19:14: warning: multi-character character constant xx.c:20:14: warning: multi-character character constant xx.c:21:14: warning: multi-character character constant xx.c:22:14: warning: multi-character character constant xx.c:23:14: warning: multi-character character constant xx.c:24:14: warning: multi-character character constant xx.c:25:14: warning: multi-character character constant $ ./xx $ cc -o xx xx.c $ ./xx !! FAIL !! Jan/ (got -1, wanted 0) !! FAIL !! Feb/ (got -1, wanted 1) !! FAIL !! Mar/ (got -1, wanted 2) !! FAIL !! Apr/ (got -1, wanted 3) !! FAIL !! May/ (got -1, wanted 4) !! FAIL !! Jun/ (got -1, wanted 5) !! FAIL !! Jul/ (got -1, wanted 6) !! FAIL !! Aug/ (got -1, wanted 7) !! FAIL !! Sep/ (got -1, wanted 8) !! FAIL !! Oct/ (got -1, wanted 9) !! FAIL !! Nov/ (got -1, wanted 10) !! FAIL !! Dec/ (got -1, wanted 11) $ 

Note that the last test case still passed - that is, it generated a -1.

Here's a revised - more verbose - version of parseMonth() which does work the same under both GCC and Sun C compiler:

#include <stdio.h>  /* MONTH_CODE("Jan/") does not reduce to an integer constant */ #define MONTH_CODE(x)   ((((((x[0]<<8)|x[1])<<8)|x[2])<<8)|x[3])  #define MONTH_JAN       (((((('J'<<8)|'a')<<8)|'n')<<8)|'/') #define MONTH_FEB       (((((('F'<<8)|'e')<<8)|'b')<<8)|'/') #define MONTH_MAR       (((((('M'<<8)|'a')<<8)|'r')<<8)|'/') #define MONTH_APR       (((((('A'<<8)|'p')<<8)|'r')<<8)|'/') #define MONTH_MAY       (((((('M'<<8)|'a')<<8)|'y')<<8)|'/') #define MONTH_JUN       (((((('J'<<8)|'u')<<8)|'n')<<8)|'/') #define MONTH_JUL       (((((('J'<<8)|'u')<<8)|'l')<<8)|'/') #define MONTH_AUG       (((((('A'<<8)|'u')<<8)|'g')<<8)|'/') #define MONTH_SEP       (((((('S'<<8)|'e')<<8)|'p')<<8)|'/') #define MONTH_OCT       (((((('O'<<8)|'c')<<8)|'t')<<8)|'/') #define MONTH_NOV       (((((('N'<<8)|'o')<<8)|'v')<<8)|'/') #define MONTH_DEC       (((((('D'<<8)|'e')<<8)|'c')<<8)|'/')  static int parseMonth(const char *input) {     int rv=-1;     int inputInt=0;     int i=0;      for(i=0; i<4 && input[i]; i++) {         inputInt = (inputInt << 8) | input[i];     }      switch(inputInt) {         case MONTH_JAN: rv=0; break;         case MONTH_FEB: rv=1; break;         case MONTH_MAR: rv=2; break;         case MONTH_APR: rv=3; break;         case MONTH_MAY: rv=4; break;         case MONTH_JUN: rv=5; break;         case MONTH_JUL: rv=6; break;         case MONTH_AUG: rv=7; break;         case MONTH_SEP: rv=8; break;         case MONTH_OCT: rv=9; break;         case MONTH_NOV: rv=10; break;         case MONTH_DEC: rv=11; break;     }      return rv; }  static const struct {     char *data;     int   result; } test_case[] = {     { "Jan/", 0 },     { "Feb/", 1 },     { "Mar/", 2 },     { "Apr/", 3 },     { "May/", 4 },     { "Jun/", 5 },     { "Jul/", 6 },     { "Aug/", 7 },     { "Sep/", 8 },     { "Oct/", 9 },     { "Nov/", 10 },     { "Dec/", 11 },     { "aJ/n", -1 },     { "/naJ", -1 }, };  #define DIM(x) (sizeof(x)/sizeof(*(x)))  int main(void) {     size_t i;     int    result;      for (i = 0; i < DIM(test_case); i++)     {         result = parseMonth(test_case[i].data);         if (result != test_case[i].result)             printf("!! FAIL !! %s (got %d, wanted %d)\n",                    test_case[i].data, result, test_case[i].result);     }     return(0); } 

I wanted to use MONTH_CODE() but the compilers did not cooperate.

like image 101
Jonathan Leffler Avatar answered Nov 08 '22 18:11

Jonathan Leffler


if ( !input[0] || !input[1] || !input[2] || input[3] != '/' )     return -1;  switch ( input[0] ) {     case 'F': return 1; // Feb     case 'S': return 8; // Sep     case 'O': return 9; // Oct     case 'N': return 10; // Nov     case 'D': return 11; // Dec;     case 'A': return input[1] == 'p' ? 3 : 7; // Apr, Aug     case 'M': return input[2] == 'r' ? 2 : 4; // Mar, May     default: return input[1] == 'a' ? 0 : (input[2] == 'n' ? 5 : 6); // Jan, Jun, Jul } 

Slightly less readable and not so much validating, but perhaps even faster, no?

like image 20
Vilx- Avatar answered Nov 08 '22 17:11

Vilx-