Thread: weird cross-platform problem

  1. #1
    Registered User watertonian's Avatar
    Join Date
    May 2012
    Location
    SE Wisconsin
    Posts
    5

    Question weird cross-platform problem

    Hello all. 1st post here . Anyway, I'm having some trouble with a straight-up ansi C program I'm trying to compile. I wrote it on my Amiga, for which I use GCC 2.95.3 to compile. It compiles fine, without as much as a warning, and it works well (It just splits up a thumbs.db file into its component .jpg files). Thinking I could use something like this on my Netbook (with Ubuntu Linux), I copied the code over, and re-compiled with GCC 4.6.1. I got a few errors at first, but sorted all that out after manually including headers that the Amiga version seems to do automatically, as well as change an include filename (volume: path/file.h to /path/file.h. actually, just file.h as I put the header in the same directory for the Linux compile).
    After working out the minor differences, it compiled fine, again with no warnings. Then it gets a "segmentation fault" immediatly after running. I tried using the -ggdb debugger switch, and using gdb, which seems to have tracked it to an fclose() statement (there are 2 which the program would actually run), but I can't pin it down any more than that. Anybody know what I'm doing wrong here? (Any advise on better ways of doing whatever it is that might be ineffective is welcome, too ).

    P.S. Found the fclose() problem, apparently having that close a pointer that didn't open due to a file not found doesn't work that well... I really should drink more coffee before attempting this sort of thing. (Not a prob on the Amiga, as windows insistance at capitalizing "Thumbs.db" doesn't really make much difference in a non case-sensitive fs). But now it chokes on the malloc() statement....
    winthumbs.c
    Code:
    #include<stdio.h>
    // added #include <string.h> here for linux
    #include<malloc.h>
    #include"code:felix/quickfile.h" // changed to #include"quickfile.h" for linux
    
    int main(int argc,char *argv[])
    {
     int ecode=0;
     int count=0;
     char *filename="thumbs.db";
     char *outname="thumb";
     char *outext="jpg";
     char outfilename[255];
     char *thumbfile;
     char *jfifhead="\xff\xd8\xff";
     char testhead[3];
    // unsigned char eothead[3];
     char *eothead="\xff\xd9";
     char *thumbhead="\xD0\xCF";
     char echeck[30];
     int thumblen=0;
     int thumbcount=0;
     int outsize=0;
     int quitloop=0;
     FILE *outfile;
     if(argc>1) filename=argv[20];
     thumblen=getfilesize(filename);
     if(thumblen>0)
     {
    /*  eothead[0]=0xff;
      eothead[1]=0xd9;
      eothead[2]=0;
    */  sprintf(testhead,"%s",jfifhead);
      printf("%s\n",quickfileversion());
      thumbfile=quickload(thumbfile,filename,NULL);
      printf("filename \33[32m%s\33[39m(\33[36m%i\33[39mB) loading\n",filename,thumblen,thumbhead);
      printf("\33[32mDONE!\33[39m scanning for jfif data.\n");
      for(count=0;count<(thumblen-3);count++)
      {
       if((thumbfile[count]==testhead[0])&&(thumbfile[count+1]==testhead[1])&&(thumbfile[count+2]==testhead[2]))
       {
        thumbcount++;
        printf("found \33[35m%.4i\33[39m thumbs ($\33[32m%.8X\33[39m)\n", thumbcount,count);
        sprintf(outfilename,"%s%.4i.%s",outname,thumbcount,outext);
        printf("Saving \33[36m%s\33[39m... ",outfilename);
        if(outfile=fopen(outfilename,"w"))
        {
         quitloop=0;
         sprintf(testhead,"%s",eothead);
         while((count<thumblen)&&(quitloop==0))
         {
          if((thumbfile[count]==testhead[0])&&(thumbfile[count+1]==testhead[1]))
          {
           printf("\33[32m EOF \33[39m");
           fprintf(outfile,"%s",eothead);
    //       fprintf(outfile,"%s",eothead);
           quitloop=1;
           outsize=outsize+strlen(eothead);
           count--;
          }
          else
          {
           fprintf(outfile,"%c",(unsigned char)thumbfile[count]);
           count++;
           outsize++;
          };
         };
         sprintf(testhead,"%s",jfifhead);
        }
        else
        {
         printf("\n \33[31mFILE ERROR!\33[39m\n");
        };
        fclose(outfile);
        printf("\33[31mDONE!\33[39m (\33[32m%i\33[39mB)\n", outsize);
        outsize=0;
       };
      };
     };
     return(ecode);
    };
    quickfile.h
    Code:
    /* quickfile.h */
    char *quickfile_errors[]={"No Error", "Memory Error", "File not found", "Save file error", "Wrong file type", NULL};
    enum {quickfile_noerror,quickfile_memoryerror,quickfile_notfounderror,quickfile_saveerror,quickfile_wrongfile};
    char *quickload(char *filebuffer, char *filename, char *header);
    int quicksave(char *filebuffer, char *filename, char *header);
    int getfilesize(char *filename);
    char *quickfileversion();
    
    int getfilesize(char *filename)
    {
     int errcode=0;
     int filesize=0;
     FILE *infile;
     if(infile=fopen(filename, "r"))
     {
      fseek(infile, 0, SEEK_END);
      filesize=(ftell(infile)+1)*sizeof(char);
      errcode=1+(filesize*sizeof(char));
     };
     fclose(infile);
     return(errcode);
    };
    
    char *quickload(char *filebuffer, char *filename, char *header)
    {
     int ecode=0;
     int filesize=0;
     int headersize=0;
     int count=0;
     int headeroffset=0;
     FILE *inputfile;
     if(inputfile=fopen(filename,"r"))
     {
      fseek(inputfile,0,SEEK_END);
      filesize=(ftell(inputfile)+1)*sizeof(char);
      filebuffer=(char *)realloc((char *)filebuffer,filesize);
      if(filebuffer==NULL)
      {
       filebuffer=(char *)realloc((char *)filebuffer,(strlen(quickfile_errors[quickfile_memoryerror])+1));
       sprintf(filebuffer,"%s",quickfile_errors[quickfile_memoryerror]);
      }
      else
      {
       filesize--;
       fseek(inputfile,0,SEEK_SET);
       if(header!=NULL)
       {
        headersize=strlen(header);
       }
       else
       {
        headersize=-1;
       };
       for(count=0;count<filesize;count++)
       {
        if(count==headersize) 
        {
         headeroffset=count;
         filebuffer[count]=0;
         if(strcmp(filebuffer,header)!=0)
         {
          count=filesize;
          filebuffer=(char *)realloc((char *)filebuffer,(strlen(quickfile_errors[quickfile_wrongfile])+1));
          sprintf(filebuffer,"%s",quickfile_errors[quickfile_wrongfile]);
          ecode=quickfile_wrongfile;
         };
        };
        filebuffer[count-headeroffset]=fgetc(inputfile);
       };
       if(ecode=quickfile_noerror)
       {
        if(header==NULL) headersize=0;
        filebuffer[filesize-headersize]=0;
       };
      };
     }
     else
     {
      filebuffer=(char *)realloc((char *)filebuffer,30);
      sprintf(filebuffer,"%s",quickfile_errors[quickfile_notfounderror]);
      ecode=quickfile_notfounderror;
     };
     fclose(inputfile);
     return(filebuffer);
    };
    
    int quicksave(char *filebuffer, char *filename, char *header)
    {
     int ecode=0;
     FILE *outputfile;
     if(outputfile=fopen(filename,"w"))
     {
      if(header==NULL)
      {
       fprintf(outputfile,"%s",filebuffer);
      }
      else
      {
       fprintf(outputfile,"%s%s",header,filebuffer);
      };
     }
     else
     {
      ecode=quickfile_saveerror;
     };
     fclose(outputfile);
     return(ecode);
    };
    
    char *quickfileversion()
    {
     char *fileversion_="vertag=|something I don't post online|";
     return(fileversion_+6);
    };
    this is what happens when I run it:
    Amiga
    Code:
    Nates shell.
    14, Ram Disk:winthumbs>dir
      thumbs.db                        winthumbs
    Nates shell.
    14, Ram Disk:winthumbs>winthumbs
    |something I don't post online|
    filename thumbs.db(31234B) loading
    DONE! scanning for jfif data.
    found 0001 thumbs ($0000080C)
    Saving thumb0001.jpg...  EOF DONE! (1086B)
    found 0002 thumbs ($00000C8C)
    Saving thumb0002.jpg...  EOF DONE! (1497B)
    found 0003 thumbs ($0000128C)
    Saving thumb0003.jpg...  EOF DONE! (3195B)
    found 0004 thumbs ($00001F4C)
    Saving thumb0004.jpg...  EOF DONE! (4129B)
    found 0005 thumbs ($00002F8C)
    Saving thumb0005.jpg...  EOF DONE! (2485B)
    found 0006 thumbs ($0000398C)
    Saving thumb0006.jpg...  EOF DONE! (3298B)
    found 0007 thumbs ($0000468C)
    Saving thumb0007.jpg...  EOF DONE! (4062B)
    found 0008 thumbs ($0000568C)
    Saving thumb0008.jpg...  EOF DONE! (2651B)
    found 0009 thumbs ($0000610C)
    Saving thumb0009.jpg...  EOF DONE! (1910B)
    found 0010 thumbs ($000068CC)
    Saving thumb0010.jpg...  EOF DONE! (3711B)
    Nates shell.
    14, Ram Disk:winthumbs>dir
      thumb0001.jpg                    thumb0002.jpg
      thumb0003.jpg                    thumb0004.jpg
      thumb0005.jpg                    thumb0006.jpg
      thumb0007.jpg                    thumb0008.jpg
      thumb0009.jpg                    thumb0010.jpg
      thumbs.db                        winthumbs
    Nates shell.
    14, Ram Disk:winthumbs>
    linux:
    Code:
    ******@k******-****:~/Desktop/test$ ls
    thumbs.db  winthumbs
    ******@k******-****:~/Desktop/test$ ./winthumbs
    |something I don't post online|
    *** glibc detected *** ./winthumbs: realloc(): invalid pointer: 0x0087672d
    ***
    ======= Backtrace: =========
    /lib/i386-linux-gnu/libc.so.6(+0x6ff22)[0x17ff22]
    /lib/i386-linux-gnu/libc.so.6(realloc+0x2a5)[0x183fc5]
    /lib/i386-linux-gnu/libc.so.6(realloc+0x2bb)[0x183fdb]
    ./winthumbs[0x80487b4]
    ./winthumbs[0x8048b0e]
    /lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x129113]
    ./winthumbs[0x8048621]
    ======= Memory map: ========
    00110000-00288000 r-xp 00000000 08:07 131222     /lib/i386-linux-gnu/
    libc-2.13.so
    00288000-0028a000 r--p 00178000 08:07 131222     /lib/i386-linux-gnu/
    libc-2.13.so
    0028a000-0028b000 rw-p 0017a000 08:07 131222     /lib/i386-linux-gnu/
    libc-2.13.so
    0028b000-0028e000 rw-p 00000000 00:00 0
    00867000-00885000 r-xp 00000000 08:07 131219     /lib/i386-linux-gnu/
    ld-2.13.so
    00885000-00886000 r--p 0001d000 08:07 131219     /lib/i386-linux-gnu/
    ld-2.13.so
    00886000-00887000 rw-p 0001e000 08:07 131219     /lib/i386-linux-gnu/
    ld-2.13.so
    00caa000-00cab000 r-xp 00000000 00:00 0          [vdso]
    00e97000-00eb3000 r-xp 00000000 08:07 132026
    /lib/i386-linux-gnu/libgcc_s.so.1
    00eb3000-00eb4000 r--p 0001b000 08:07 132026
    /lib/i386-linux-gnu/libgcc_s.so.1
    00eb4000-00eb5000 rw-p 0001c000 08:07 132026
    /lib/i386-linux-gnu/libgcc_s.so.1
    08048000-0804a000 r-xp 00000000 08:07 794208
    /home/******/Desktop/test/winthumbs
    0804a000-0804b000 r--p 00001000 08:07 794208
    /home/******/Desktop/test/winthumbs
    0804b000-0804c000 rw-p 00002000 08:07 794208
    /home/******/Desktop/test/winthumbs
    08d46000-08d67000 rw-p 00000000 00:00 0          [heap]
    b775c000-b775d000 rw-p 00000000 00:00 0
    b7772000-b7776000 rw-p 00000000 00:00 0
    bfce8000-bfd09000 rw-p 00000000 00:00 0          [stack]
    Aborted
    ******@***********:~/Desktop/test$
    Last edited by watertonian; 05-20-2012 at 01:13 AM. Reason: confusion with <cr><lf> between the Amiga and this site??

  2. #2
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    First reply, of sorts.

    Imagine you were on a forum with some relevant knowledge of C programming, and willing to help folks with problems, all without being paid to do it.

    Now, read your post, and ask whether it articulates a problem in an understandable manner? Would you help someone who created a post like that?

    In my case, the answer to both of the questions I have asked is .... No.
    Right 98% of the time, and don't care about the other 3%.

    If I seem grumpy or unhelpful in reply to you, or tell you you need to demonstrate more effort before you can expect help, it is likely you deserve it. Suck it up, Buttercup, and read this, this, and this before posting again.

  3. #3
    Registered User watertonian's Avatar
    Join Date
    May 2012
    Location
    SE Wisconsin
    Posts
    5
    er.. sorry about that, guess what I need to know is why this works on one OS and not the other? Found out half-way through the post about the malloc() issue, which seems to be the true problem. I think its because I'm trying to realloc() a pointer that was passed to a function, which I thought I had down (Works on the Amiga, not on Linux, haven't tried Windows yet).The troublesome realloc() command is in the quickfile.h file in the quickload() function. Is there a more compatable way of doing that, without resorting to globals?

  4. #4
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    Few things.

    You should be including <stdlib.h>, not <malloc.h>. You should also not be casting the return values of malloc/realloc.
    Header files should not contain code.
    You should always include <string.h> if you're using str* functions.
    Your "cross-platform problem" is an "undefined behavior" problem. You're modifying the location to where a pointer is pointing within a function, and this modification is not returned to the caller because you're modifying a local copy of the variable. And you never test the return values of the allocs.

    Compare the results of this program, first #define-ing TEST_FAIL and then not #define-ing TEST_FAIL:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #if TEST_FAIL
    void test(char *ptr, const size_t len)
    {
    	ptr = malloc(len);
    }
    #else
    void test(char **ptr, const size_t len)
    {
    	*ptr = malloc(len);
    }
    #endif
    
    int main()
    {
    	char *hello = NULL;
    
    #if TEST_FAIL
    	test(hello, strlen("hello") + 1);
    #else
    	test(&hello, strlen("hello") + 1);
    #endif
    	if (!hello)
    	{
    		fprintf(stderr, "Memory allocation failed!\n");
    		return EXIT_FAILURE;
    	}
    	strcpy(hello, "hello");
    	printf("Result: %s\n", hello);
    	return EXIT_SUCCESS;
    }
    Code:
    $ gcc -DTEST_FAIL -ggdb3 -Wall -pedantic -o malloc_test malloc_test.c 
    $ ./malloc_test
    Memory allocation failed!
    $
    Code:
    $ gcc -ggdb3 -Wall -pedantic -o malloc_test malloc_test.c 
    $ ./malloc_test
    Result: hello
    $

  5. #5
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    Is it so hard to see that thumbfile is an uninitialised pointer that you're passing to quickload() (line36), which is then passed to realloc?

    If you initialise this pointer to NULL, your realloc will succeed.

    But see also the post from r2r about returning a modified pointer from a function.

    Since quickload() returns a pointer, there is no point passing a pointer (initialised or otherwise) into the function to begin with.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  6. #6
    Registered User watertonian's Avatar
    Join Date
    May 2012
    Location
    SE Wisconsin
    Posts
    5
    OK, thanks all. Looks like I was trying to do some rather unconventional stuff trying to be lazy (I originally wrote quickfile.h so I wouldn't have to mess around with reallocating and loading stuff manually). I fixed the immediate issue by defining char *thumbfile as a global, and it works fine now. At least most of the time... Apparently, Windows Thumbs.db files have some weird encoding in them that prevents simply breaking the file apart from working 100% of the time..Anyway, one thing I don't understand, why stdlib.h instead of malloc.h? I'm working off of C++ In Plain English, 2nd edition (ISBN 0-7645-4572-8), which seems pretty vague about the subject.. (Though quite useful on many other subjects, if the coffee stains/stickit-note-bookmarks/general "beat-up" look is any clue)Though its curious that the Amiga and Linux versions of the same (if different versions) compiler would act that differently.. Probably how it ties into the OS, my guess would be AmigaOS's lack of memory protection...

  7. #7
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    There is no reason on earth why a correctly written program would not work the same on all three platforms.

    First off, your "solution" of making a variable global is just awful.
    char *thumbfile = NULL;
    would have been just as effective (it initialised it).

    > Anyway, one thing I don't understand, why stdlib.h instead of malloc.h?
    Because that's what the standard says. The prototype for malloc is in stdlib.h
    It might be in other header files as well (for reasons of compatibility with a particular OS/Compiler), but if you want portable code, then use the standard header files.

    > Though its curious that the Amiga and Linux versions of the same (if different versions) compiler would act that differently
    Have you even read the posts in this thread, or just hacked away until the problem was sufficiently masked to allow the code to run?
    It works differently because your code was broken!

    The fact that it "worked" on Amiga was down to pure dumb luck on your part (say for example that on the Amiga, you just got lucky and thumbfile was always NULL).

    Remember, you stopped debugging your Amiga code when it stopped crashing, NOT when it was bug-free.
    So when you ran the code on Linux, you found more bugs - congratulations.

    Making the program work correctly on two systems at the same time is going to produce a program which has even fewer bugs. It might then work on Windows right away (or it might not).

    With regard to books in general, it's a good idea to not rely on any single source of information.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  8. #8
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    Writing code that "works" on one platform is easy.

    Writing code that "works" on multiple platforms is harder.

    Writing code that will work, automatically, without changes, and on any standardised C compiler on any platform is a lot harder still.

    When you only work on one platform (which I would hazard that the majority of casual programmers do), there are myriad things that you can do and miss and just assume they would work elsewhere (these forums are filled with people #include'ing conio.h, for example, among other things). It doesn't usually matter that much because "Hey, the program works! Thanks guys!" or similar and off they trundle, happy with their single result.

    As soon as you start working on multiple platforms, all these niggly little things that people nag about make a big difference. That's *why* those nagging programmers nag, and why they've acquired "odd" habits (such as #include'ing the right files, not using certain constructs, checking every command for failure, not assuming struct alignments are the same, etc.) - because they've been stung when they've moved code to other platforms in the past and, to lessen the hassle, always code without such assumptions all the time. It's also just good practice - if your compiler setup is irrecoverably destroyed (e.g. your compiler is made obsolete or your computer blows up, etc.), you may be forced onto a different OS, architecture, compiler and all your previously-working projects will just stop working. This isn't as far-fetched as it sounds. Soon you won't be ABLE to buy a 32-bit operating system on a cheap PC. So when your computer goes bang and you dig out an emergency machine to finish off your programming project, you better hope that you took account that pointers might be a different size, pointers may not be castable to integers, etc.

    And, let's be honest, most people who learn programming will code only for themselves (and maybe their tutors) while learning. But people who program otherwise have the ultimate intention to give their program to *somebody* at the end, whether that's by selling their game, or distributing their utility, or contributing their code to an open-source project or whatever. And the second you do that, the chances of the people you share the program with having an identical (or even directly compatible) computer setup drop sharply. Even on Steam (to pluck a random example), I've seen programs that assume you always have only one joystick plugged in (one big-name game used to crash if you plugged another in!), assume you are running with Gb's of disk space available without bothering to check, assume that nobody uses Window XP any more (despite the game coming out when only XP existed as a viable games platform, thus breaking the game for your oldest users instantly!), etc. So even the "professionals" make mistakes in this area, usually because they aren't used to programming for other people, only themselves (I've seen one game recently that crashed because it never realised there WERE 16:10 ratio resolutions, for example).

    It's like the difference between pseudo-science and real science (because it is - I studied "Computer Science", personally). Pseudo-science will say "Hey, I saw a guy who couldn't lick his own elbows, so it must be impossible!". Science says "One example does not make a proof, and the specific does not imply the general". Just because your program works on ONE platform, it doesn't mean it will work on ANY other unless you specifically took this into account on EVERY SINGLE LINE and tested your code too. The only thing that is consistent between all C compilers is the C standards supported (e.g. C99, etc.) and even there you can run into odd corner cases of unspecified behaviour. Program ONLY to a C standard (which would have stopped all the above problems you had, really) and your program will be fully portable to any standard-compliant compiler on any platform. Believe it or not, this doesn't even directly translate to C++ or C++0x or the newer C standards yet, of which there are shockingly few compliant implementations (and even gcc isn't really C99 compliant in EVERY way, even if you use the non-default "pretend to be C99 compliant" switches!).

    And, as you've noticed, the problem even extends to published books. Hell, I still see C For Dummies editions being sold that start with DOS and VGA graphics programming using TurboC. God knows what new coders must think when they try to make sense of that book with a modern setup! That's why these forums have 50% of new posts with "void main" and similar. And it's not a problem that will go away - smartphones are not only different speeds to PC's but different architectures too (ARM, etc.). Windows will support ARM tablets in the future. The Raspberry Pi is an ARM platform. Android runs on ARM. And on ARM, compared to x86, there are a lot of fundamental differences that only the C standardised-programming will avoid or make transparent to the programmer.

    C was written to make porting programs between very different architectures as simple as possible. But as soon as you stray from the standard, you run into problems. For example, why your compiler needs that odd Amiga include baffles me unless it's a hard-coded pathname (which should be fixed by just including the bare filename and adjusting the compiler's include paths instead of trying to hard-code a path into the code which means anyone with an Amiga and your code installed in a DIFFERENT pathname is immediately stopped from compiling it). Also, why don't you include string.h in the file, regardless of platform? It's a standard file and should be present on any standard C implementation.

    It's the difference between making a program that "should" work and one that "will" work. If you're serious about programming (i.e. ever intend other people to use your programs), the second option saves you MUCH more hassle in the long run.

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

  9. #9
    Registered User watertonian's Avatar
    Join Date
    May 2012
    Location
    SE Wisconsin
    Posts
    5
    Yeah, my books are kinda old (C++ reference is ©1999), and with my "budget", most reference materials (hard-copy) are purchased at thrift-shops, garage sales, and Public Library "Too old to be usefule" sales... Also, swithcing the pointer back to a local and setting to NULL did work, I just flipped it to global to get the thing to work. (The whole idea was to see if some other bugs persisted on a different operating system, or if it was Amiga specific, namely some .jpg files were corrupt and I wasn't sure if the Amiga datatypes were to blame, or if it was something else. Looks like something else, though).This particular program probably won't get ported (in any serious capacity) to Windows or Linux, as there are programs for both that do a much better job than my code currently does, and I would rather port something useful. Little experiments like this do, as previously mentioned, indicate a few things to look out for, though. Having started programming via BASIC on a C= Vic-20 (not to advertise my age), there were a few coceptual differences to get used to, and I'm afraid pointers happen to be one of them (and getting used to such things on a system as bizzare as the Amiga probably doesn't help). At least when switching to Linux for mainstream use I'll be used to BE/LE stuff. Not that I've encountered many probs so far..

  10. #10
    [](){}(); manasij7479's Avatar
    Join Date
    Feb 2011
    Location
    *nullptr
    Posts
    2,657
    Quote Originally Posted by watertonian View Post
    Yeah, my books are kinda old (C++ reference is ©1999), and with my "budget", most reference materials (hard-copy) are purchased at thrift-shops, garage sales, and Public Library "Too old to be usefule" sales...
    Nowadays, a lot of good documentation is distributed digitally for free.
    Since you mentioned C++, cppreference.com does a great job and this ( C++ Annotations | Free Development software downloads at SourceForge.net ) is a great modern C++ reference and tutorial book.

  11. #11
    Registered User watertonian's Avatar
    Join Date
    May 2012
    Location
    SE Wisconsin
    Posts
    5
    I actually have those bookmarked after finding them this weekend.

  12. #12
    Registered User ledow's Avatar
    Join Date
    Dec 2011
    Posts
    435
    I have cppreference on a "quick search" in my browser (I just type "c printf" and it takes me straight to the page on cppreference). Very useful when trying to refer people to the definition of a function, etc. or to look up those little side-lines that you rarely touch ("how do I get printf to print in scientific notation again?").

    I first put it there when "relearning" C for myself a few years ago (it's so annoying to switch languages frequently and keep typing commands from the old language!), and then it's stayed there since I've been using these forums so I can check things for others that I rarely use myself. I like the tiny examples at the bottom - very handy to show what's going on even if they are rarely "correct" (return values checked, etc.) or complete.

    - Compiler warnings are like "Bridge Out Ahead" warnings. DON'T just ignore them.
    - A compiler error is something SO stupid that the compiler genuinely can't carry on with its job. A compiler warning is the compiler saying "Well, that's bloody stupid but if you WANT to ignore me..." and carrying on.
    - The best debugging tool in the world is a bunch of printf()'s for everything important around the bits you think might be wrong.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Easy cross platform dev
    By Witis in forum Tech Board
    Replies: 6
    Last Post: 01-30-2011, 09:56 AM
  2. cross platform semaphore problem
    By jet-plane in forum C Programming
    Replies: 0
    Last Post: 05-24-2008, 01:59 PM
  3. Cross-Platform GUI
    By @nthony in forum C++ Programming
    Replies: 4
    Last Post: 10-24-2007, 02:51 PM
  4. wxWidgets cross platform GUI problem
    By BobS0327 in forum Linux Programming
    Replies: 2
    Last Post: 05-31-2006, 06:34 AM
  5. Cross platform question
    By ~Kyo~ in forum Game Programming
    Replies: 8
    Last Post: 08-25-2005, 04:35 PM