Thread: Professional coding

  1. #1
    Registered User
    Join Date
    Feb 2011
    Posts
    144

    Professional coding

    Hi, all. I previously started a thread on how to get a code review. Based on the responses, I've started an extensive refactorization of my code, and I'd like some advice on how I'm going. Here's my main() function, and the next function deep. This is a Wikipedia bot, which works perfectly. I have open sourced it.

    I find this style of programming far more difficult to understand than the scheme I was using before. Also, because the program is so complicated, I am worried about the sheer number of variables that are going to exist by the time I get to main3 () and main4(). Am I on the right track here, or not?

    Code:
    #include <stdlib.h>
    #include <string.h>
    #include <curl/curl.h>
    
    #include "Printtime.h"
    #include "Preferences.h"
    #include "Managelogfile.h"
    #include "Main2.h"
    
    #include "Safeprint.h"
    #include "Variables.h"
    
    // TODO : Remove global variables.
    
    static int shutdownmessage ( void ) ;
    
    int main ( int argc , char* argv [] )
    {
    				/* If any of these is set to 1, we will exit without improving Wikipedia. */
    	unsigned int uidisplayversion = 0 , uidisplayhelp = 0 , uibadparameter = 0 ;		
    
    	struct preferencesstruct preferences ;		/* All our preferences go here. */
    	memset ( &preferences , 0 , sizeof ( struct preferencesstruct ) ) ;
    
    	for ( int arg = 1 ; arg < argc ; arg ++ )	/* Parse command line options. */
    	{
    		if ( strcmp ( argv [ arg ] , "highmaxlag" ) == 0 )	/* highmaxlag */
    			{ strcpy ( szmaxlag , "20" ) ; preferences.highmaxlag = 1 ; }
    		
    		else if ( strcmp ( argv [ arg ] , "nodump" ) == 0 )	/* nodump */
    			{ uidumpbuffers = 0 ; preferences.nodump = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "nolog" ) == 0 )	/* nolog */
    			{ uinolog = 1 ; preferences.nolog = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "noloop" ) == 0 )	/* noloop */
    			{ uiimprovementscanloop = 0 ; preferences.noloop = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "noshutoff" ) == 0 )	/* noshutoff */
    			{ uinoshutoff = 1 ; preferences.noshutoff = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "nostatus" ) == 0 )	/* nostatus */
    			{ uistatusupdate = 0 ; preferences.nostatus = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "persevere" ) == 0 )	/* persevere */
    			preferences.persevere = 1 ;
    
    		else if ( strcmp ( argv [ arg ] , "progressmeter" ) == 0 ) /* progressmeter */
    			{ uiprogressmeter = 1 ; preferences.progressmeter = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "quick" ) == 0 )	/* quick */
    		{
    			uisecondsbetweenimprovements = 2 ;
    			uisecondsbetweenimprovementscans = 2 ;
    			uisecondsbetweenfailedhttprequests = 5 ;
    			uiextrasecondsbetweenthrottledloginrequests = 120 ;
    			preferences.quick = 1 ;
    		}
    
    		else if ( strcmp ( argv [ arg ] , "silent" ) == 0 )	/* silent */
    			{ uisilentmode = 1 ; preferences.silent = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "simulate" ) == 0 )	/* simulate */
    			{ uisimulate = 1 ; preferences.simulate = 1 ; }
    
    		else if ( strcmp ( argv [ arg ] , "verbose" ) == 0 )	/* verbose */
    			{ uiverbose = 1 ; preferences.verbose = 1 ; }
    
    		else if	 ( ( strcmp ( argv [ arg ] , "v" ) == 0 )		/* version (or one of 5 synonyms) */
    			|| ( strcmp ( argv [ arg ] , "version" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "-v" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "-version" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "--v" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "--version" ) == 0 ) ) 							 
    				uidisplayversion = 1 ;
    
    		else if	 ( ( strcmp ( argv [ arg ] , "h" ) == 0 )	/* help (or one of 5 synonyms) */
    			|| ( strcmp ( argv [ arg ] , "help" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "-h" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "-help" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "--h" ) == 0 )
    			|| ( strcmp ( argv [ arg ] , "--help" ) == 0 ) )
    				uidisplayhelp = 1 ;
    
    		else 
    		{
    			if ( safeprintf ( "Unrecognized command line option : %s\n" , argv [ arg ] ) < 0 ) 
    					return EXIT_FAILURE ;
    			uibadparameter = 1 ;
    		}
    	}
    
    	if ( uibadparameter )
    	{
    		uisilentmode = 0 ;
    		preferences.silent = 0 ;
    		if ( uidisplayversion ) { safeprint ( szversionmessage ) ; 
    					  safeprintf ( "Libcurl version : %s\n" , curl_version() ) ; }
    		safeprint ( szusagemessage ) ;
    		return EXIT_FAILURE ;					/* Exit without improving Wikipedia. */
    	}
    
    	if ( uidisplayversion )
    	{
    		uisilentmode = 0 ;
    		preferences.silent = 0 ;
    		if ( safeprint ( szversionmessage ) < 0 ) return EXIT_FAILURE ;
    		if ( safeprintf ( "Libcurl version : %s\n" , curl_version() ) < 0 ) return EXIT_FAILURE ;
    		if ( ( uidisplayhelp ) && ( safeprint ( szusagemessage ) < 0 ) ) return EXIT_FAILURE ;
    		return EXIT_SUCCESS ;					/* Exit without improving Wikipedia. */
    	}
    
    	if ( uidisplayhelp )
    	{
    		uisilentmode = 0 ;
    		preferences.silent = 0 ;
    		if ( safeprint ( szusagemessage ) < 0 ) return EXIT_FAILURE ;
    		return EXIT_SUCCESS ;					/* Exit without improving Wikipedia. */
    	}
    
    	if ( ( safeprint ( szstartupmessage ) < 0 ) 
    	|| ( safeprint ( szbuildmessage ) < 0 )
    	|| ( safeprint ( "Bot started at : " ) < 0 )
    	|| ( printtime () < 0 ) )					/* Produces a terminating '\n'. */
    		return EXIT_FAILURE ;
    
    	if ( eraseoldlogfiles () < 0 ) { shutdownmessage () ; return EXIT_FAILURE ; }
    
    	FILE *logfile = 0 ;
    
    	if ( preferences.nolog == 0 )
    		if ( ( logfile = startuplogfile () ) == NULL ) { shutdownmessage () ; return EXIT_FAILURE ; }
    
    	if ( main2 ( logfile , preferences ) < 0 )		/* Go one level deeper. */
    	{  
    		shutdownmessage () ; 
    		if ( preferences.nolog == 0 ) shutdownlogfile ( logfile ) ; 
    		return EXIT_FAILURE ; 
    	}
    
    	if ( shutdownmessage () < 0 )
    	{
    		if ( preferences.nolog == 0 ) shutdownlogfile ( logfile ) ;
    		return EXIT_FAILURE ;
    	}
    
    	if ( preferences.nolog == 0 ) 
    		if ( shutdownlogfile ( logfile ) < 0 ) return EXIT_FAILURE ;
    
    	return EXIT_SUCCESS ;
    }
    
    static int shutdownmessage ( void )
    {
    	if ( ( safeprint ( szshutdownmessage ) < 0 )
    	|| ( safeprint ( "Bot shutdown at : " ) < 0 )
    	|| ( printtime () < 0 ) )					/* Produces a terminating '\n'. */
    	return -1 ;
    
    	return 0 ;
    }
    
    // Main2.c
    
    #include <stdlib.h>
    #include <stdio.h>
    #include <curl/curl.h>
    
    #include "Preferences.h"
    #include "Buffers.h"
    #include "Httpdatamemorystruct.h"
    #include "Httpdatamemorystructs.h"
    #include "Startupandshutdownbot.h"
    #include "Improvewikipedia.h"
    
    #include "Safeprint.h"
    #include "Error.h"
    
    int main2 ( FILE *logfile , struct preferencesstruct preferences )
    {
    	pheaderbuffer = ( char* ) malloc ( buffersize ) ;
    	if ( pheaderbuffer == NULL )
    	{
    		error ( "HTML header buffer could not be allocated." ) ;
    		return -1 ;
    	}
    	pheaderbuffer [ 0 ] = 0 ;
    
    	pbodybuffer = ( char* ) malloc ( buffersize ) ;
    	if ( pbodybuffer == NULL )
    	{
    		error ( "HTML body buffer could not be allocated." ) ;
    		free ( pheaderbuffer ) ;
    		return -1 ;
    	}
    	pbodybuffer [ 0 ] = 0 ;
    
    	pwikitextbuffer = ( char* ) malloc ( buffersize ) ;
    	if ( pwikitextbuffer == NULL )
    	{
    		error ( "Wikitext buffer could not be allocated." ) ;
    		free ( pheaderbuffer ) ;
    		free ( pbodybuffer ) ;
    		return -1 ;
    	}
    	pwikitextbuffer [ 0 ] = 0 ;
    
    	phtmlrenderbuffer = ( char* ) malloc ( buffersize ) ;
    	if ( phtmlrenderbuffer == NULL )
    	{
    		error ( "HTML render buffer could not be allocated." ) ;
    		free ( pheaderbuffer ) ;
    		free ( pbodybuffer ) ;
    		free ( pwikitextbuffer ) ;
    		return -1 ;
    	}
    
    	phtmlrenderbuffer [ 0 ] = 0 ;
    
    	ppastrevidbuffer = ( char* ) malloc ( buffersize ) ;
    	if ( ppastrevidbuffer == NULL )
    	{
    		error ( "Past revision buffer could not be allocated." ) ;
    		free ( pheaderbuffer ) ;
    		free ( pbodybuffer ) ;
    		free ( pwikitextbuffer ) ;
    		free ( phtmlrenderbuffer ) ;
    		return -1 ;
    	}
    	ppastrevidbuffer [ 0 ] = 0 ;
    
    	peditbuffer = ( char* ) malloc ( buffersize ) ;
    	if ( peditbuffer == NULL )
    	{
    		error ( "Edit buffer could not be allocated." ) ;
    		free ( pheaderbuffer ) ;
    		free ( pbodybuffer ) ;
    		free ( pwikitextbuffer ) ;
    		free ( phtmlrenderbuffer ) ;
    		free ( ppastrevidbuffer ) ;
    		return -1 ;
    	}
    	peditbuffer [ 0 ] = 0 ;
    
    	// TODO : Eliminate these globals.
    
    	szeditsummary [ 0 ] = 0 ;	/* Set all of our strings to "". */
    	szedittoken [ 0 ] = 0 ;
    	szlogintoken [ 0 ] = 0 ;
    	sztimestamp [ 0 ] = 0 ;
    	szauthor [ 0 ] = 0 ;
    	szpastauthor [ 0 ] = 0 ;
    	szpastrevid [ 0 ] = 0 ;
    
    	uiedittokenexists = 0 ;		/* Once set, these persist from one HTTP request to the next. */
    	uilogintokenexists = 0 ;
    	uieditsummaryvalid = 0 ;
    	uitimestampvalid = 0 ;
    	uiauthorvalid = 0 ;
    	uipastauthorvalid = 0 ;
    
    	headerchunk.stdatasize = 0 ;	/* Reset the pointers to our HTTP data buffers. */
    	bodychunk.stdatasize = 0 ;
    
    	int res = 0 ;
    
    	if ( ( safeprint ( "We are using libcurl. Version information :\n" ) == 0 )
    	   && ( safeprintf ( "%s\n" , curl_version () ) == 0 ) )
    	{
    		if ( curl_global_init ( CURL_GLOBAL_ALL ) == 0 )
    		{
    			if ( safeprint ( "Libcurl initialized successfully.\n" ) == 0 ) /* Announce our success. */
    			{
    				if ( startupbot () == 0 )
    				{
    
    
    
    					do
    					{
    						res = improvewikipedia () ;	/* The main stuff. */
    					} while ( ( res == -1 ) && ( preferences.persevere ) ) ;	
    						/* If we're persevering, ignore fatal return codes. */
    
    	
    
    				}
    			}
    			else
    				error ( "Couldn't deliver message." ) ;
    
    			curl_global_cleanup () ;	/* (void) */
    
    		 	if ( safeprint ( "Libcurl cleaned up successfully.\n" ) < 0 )  	 /* Announce our success. */
    			{
    				error ( "Couldn't deliver message." ) ;
    				free ( pheaderbuffer ) ;
    				free ( pbodybuffer ) ;
    				free ( pwikitextbuffer ) ;
    				free ( phtmlrenderbuffer ) ;
    				free ( ppastrevidbuffer ) ;
    				free ( peditbuffer ) ;
    				shutdownbot () ;
    				return -1 ;
    			}
    		}
    		else 
    			error ( "Couldn't initialize libcurl." ) ;
    	}
    	else
    		error ( "Couldn't deliver message." ) ;
    
    	free ( pheaderbuffer ) ;
    	free ( pbodybuffer ) ;
    	free ( pwikitextbuffer ) ;
    	free ( phtmlrenderbuffer ) ;
    	free ( ppastrevidbuffer ) ;
    	free ( peditbuffer ) ;
    
    	if ( shutdownbot () < 0 ) return -1 ;
    
    	if ( res < 0 )
    	{
    		return -1 ;
    	}
    
    	return 0 ;
    }

  2. #2
    ATH0 quzah's Avatar
    Join Date
    Oct 2001
    Posts
    14,826
    Quote Originally Posted by Richardcavell View Post
    Hi, all. I previously started a thread on how to get a code review....Am I on the right track here, or not?
    Was there some particular reason you felt like starting a new thread for the same topic?


    Quzah.
    Hope is the first step on the road to disappointment.

  3. #3
    Registered User
    Join Date
    Feb 2011
    Posts
    144

    Yes

    Yes, because the topic changed from my original topic, which was "How to get a code review". Now my question is "Is my code good?"

  4. #4
    Registered User
    Join Date
    Jun 2005
    Posts
    6,815
    Quote Originally Posted by Richardcavell View Post
    I find this style of programming far more difficult to understand than the scheme I was using before. Also, because the program is so complicated, I am worried about the sheer number of variables that are going to exist by the time I get to main3 () and main4(). Am I on the right track here, or not?
    If you are having trouble understanding your own code, then you're definitely on the wrong track.

    The point of coding style and also of refactoring is getting your code into a form that is clear and easy to understand. If, six months after writing your code, you need to struggle to understand it you will not be able to maintain it. And you can't expect anyone else to be able to maintain it either.

    Understandability of code is a hard thing to measure - what you might understand easily, I may not, and vice versa. However, if you can't understand your code, it is easy to make mistakes. And it is a tall order for someone else to understand it as well.

    As a starting point, however, try to work out what you might do to your code so you can understand it without excessive effort. Then consider what you might do to ensure that - six months from now, after you have forgotten the details of what you have done - you will be able to ensure you can read it and understand it again.
    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.

  5. #5
    Registered User
    Join Date
    Feb 2011
    Posts
    144

    Well...

    Well, I had the code arranged in a manner that I found easy to understand, where the functions were discrete, and the bot ran solid as a rock, and you people said it was unprofessional and needed to be rewritten.

  6. #6
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Ask yourself on what basis you are separating and combining these functions...
    Give the functions meaningful names... "StartLogFile" and such...

    Combine functions that relate to one another into the same translation unit... Eg: Main, SetOptions, OpenLofFile, InitLibraries etc. are all start up functions so they should be on the same page so they can communicate easily without varable scoping problems.

    Make one .h file with all your declarations and externs in it for each module of the program.

    You're doing a wikibot --which they have to approve, by the way-- so some of the logical module breaks would be Entry/Startup, Network communications, Parser, etc. There is no reason whatsoever to create more than 5 or 6 source pages for such a project.

    As I mentioned before, because you didn't bother to learn C you are doing dump trucks full of totally unnecessary work here...

  7. #7
    Registered User
    Join Date
    Feb 2011
    Posts
    144
    Should I put main2 () within main() ? If I do, then the function becomes too large to make sense at a glance, and it's difficult to visualise where each pair of curly braces start and end. I could put main2 () above main() within the same source page, and that would be alright. I can't fathom why any of these functions should be more than 100 source lines if they don't have to be.

    As to your comment that I didn't bother to learn C, I have studied K&R 2nd edition till my eyes went blurry and now I'm asking, seriously, what I need to do next. The books Effective C++ and More Effective C++ are pretty good. Are there C equivalents?

  8. #8
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by Richardcavell View Post
    Should I put main2 () within main() ? If I do, then the function becomes too large to make sense at a glance, and it's difficult to visualise where each pair of curly braces start and end.

    I could put main2 () above main() within the same source page, and that would be alright. I can't fathom why any of these functions should be more than 100 source lines if they don't have to be.
    I've written functions that are very long... one in particular (a midi file to struct array decoder) ended up at about 300 lines.

    Here's an example of what it takes to open a plain text playlist file in a unicode world. This function is on the same page as the parser and editor functions for the M3U file...

    Code:
    // open and translate file
    BOOL M3UOpen(PWCHAR FileName)
      { PBYTE  rf;      // raw file data
        DWORD  br;      // bytes read
        // load the raw file
        { HANDLE pl;    // playlist file handle 
          DWORD  fs;    // file size
          // get path to file
          wcsncpy(FilePath,FileName,MAX_PATH);
          PathRemoveFileSpec(FilePath);
          wcscat(FilePath,L"\\");
          // open the file
          pl = CreateFile(FileName,GENERIC_READ,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
          if (pl == INVALID_HANDLE_VALUE)
            Exception(GetLastError());
          fs = GetFileSize(pl,NULL);        
          rf = calloc(fs + 2, sizeof(BYTE));
          if (! ReadFile(pl, rf, fs, &br, NULL))
            Exception(GetLastError());
          CloseHandle(pl);  
          if (br != fs)
            Exception(0xE00640007); } 
        try                                   
         { DWORD bom = *(DWORD*)rf;
           if ((bom == 0x0000FEFF) || (bom == 0xFFFE0000))  // utf32le bom  
             Exception(0xE0640002);                         // utf32be bom  
           else if ((bom & 0xFFFF) == 0xFFFE)               // utf16be bom
             { FlipEndian(rf,br);
               CopyWchar((PWCHAR) rf + 1); }
           else if ((bom & 0xFFFF) == 0xFEFF)               // utf16le bom
             CopyWchar((PWCHAR) rf + 1);  
           else if ((bom & 0xFFFFFF) == 0xBFBBEF)           // utf8 bom
             CopyMByte(rf + 3, br - 3);
           else                                             // no known bom, probe the file
             { if (! memchr(rf, 0x00, br))                  // 8 bit text has no nulls
                 CopyMByte(rf,br);                          // ansi / utf8 no bom
               else 
                { PBYTE lf = memchr(rf,0x0A,br);            // lf is always present as 1 byte.
                  if (!lf) 
                    Exception(0xE0640003);
                  if ((!(*(DWORD*)(lf - 3) & 0x00FFFFFF)) ||    //utf32be no bom
                       (!(*(DWORD*)lf & 0xFFFFFF00)))           //utf32le no bom
                     Exception(0xE0640002);    
                  if ((lf - rf) & 1)                        // big endian? (lf at odd offset)
                    FlipEndian(rf,br);                      // utf16be no bom  
                  CopyWchar((PWCHAR) rf);  } } }            // utf16le no bom
         finally  
          { free(rf); }
        return 1; }
    To give you some kind of hint... For your code, I would have my main at the bottom of the page... above that would be SetCMDLOption(char * cstr) where I would pass the argv strings one at a time. The reason you're getting confused is that you are not breaking up your functions or source pages on logical barriers... It's reflective of a lack of planning.

    Before I start on a project I have a list, on paper, of what I need to do, which functions I need, which source files they're going to be in... all broken down on rational borders... Of course this gets changed as I work, but for the most part I know exactly what I need to do before I start keyboarding code.


    As to your comment that I didn't bother to learn C, I have studied K&R 2nd edition till my eyes went blurry and now I'm asking, seriously, what I need to do next. The books Effective C++ and More Effective C++ are pretty good. Are there C equivalents?
    BUT... did you do what I suggested and actually gone through the book page by page, trying the examples as you went? You can read a book like that in an evening... and you're going to retain about 10% of it. You need to sit down, do a chapter a day, do the exercises, take the quizzes; then give it time to sink in before returning to it tomorrow.

    You appear to want to go from buying the book to programming maven literally over night; your work betrays a horrible lack of patience.
    Last edited by CommonTater; 03-11-2011 at 09:02 AM.

  9. #9
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Everything you're doing is just too complex. main2(), main3(), main4()? These names mean nothing.

    The beginning of main2() is too much. You could simplify things greatly by using goto (which is not, as many may lead you to believe, something that should be avoided at all costs) to jump to an error handling section of code, remembering that free(NULL) is perfectly valid. Or at the very least, instead of 6 calls to malloc(), requiring 6 error paths, make one call (for 6 * buffersize bytes) and just point your pointers inside of it.

    Your identifiers are too difficult to read, and are often redundant. "struct preferencesstruct"? Why would you add "struct" to the end, when there's already a "struct" at the beginning? uisecondsbetweenfailedhttprequests is altogether too jumbled up. You need to pick simpler names (that are still descriptive), or at least put underscores between words. It's also confusing when so many variables start with "ui". It makes it difficult to quickly see at a glance what the name is. They all mix together.

    What you need to do is read quality code to get a feel for how it's written. I highly recommend the FreeBSD source code for a start.

  10. #10
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by cas View Post
    You could simplify things greatly by using goto (which is not, as many may lead you to believe, something that should be avoided at all costs) to jump to an error handling section of code

    Goto? Really?

    Inside the same function, rarely... between functions... NEVER.

  11. #11
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    Quote Originally Posted by CommonTater
    Goto? Really?
    cas' suggestion is one of the few legitimate uses, though I'm hesitant to suggest it to Richardcavell at this point.

    Quote Originally Posted by CommonTater
    between functions... NEVER.
    Yeah, but that's because it is illegal to use goto to jump between functions.
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  12. #12
    Registered User
    Join Date
    Dec 2007
    Posts
    2,675
    If you're running on Linux you might consider using getopt for your argument parsing/retrieval.

    Code:
    pheaderbuffer = ( char* ) malloc ( buffersize ) ;
    You should not cast the return from malloc in C.

  13. #13
    Registered User
    Join Date
    Feb 2011
    Posts
    144

    Patience

    Common Tater,

    You're like a professor I once had who read my essay and said that it was obvious that I had written it hastily the night before I handed it in, when in fact I had spent 6 weeks preparing it and put in far more effort than anyone else in my tutorial group. Also, the way you want me to increase code density to decrease the line count and readability, makes me think that you get paid per source code line *saved* rather than created.

    Richard
    Last edited by Richardcavell; 03-11-2011 at 10:22 AM. Reason: increase code density

  14. #14
    Registered User
    Join Date
    Sep 2007
    Posts
    1,012
    Quote Originally Posted by CommonTater View Post
    Goto? Really?

    Inside the same function, rarely... between functions... NEVER.
    Yes, really. There are legitimate uses of goto.

    I never recommended jumping between functions with goto, because you can't do that. I would recommend using setjmp() and longjmp() to jump between functions for specific purposes, too (such as exception handling).

    I realize that "never use goto" is often taught, and it's actually good advice, because those new to the language are prone to great abuse of it. But the advice is like Newton's laws: generally correct, but when you get advanced enough, you see where it breaks down.

    A decent discussion of the merits of goto in the Linux kernel is available here.

  15. #15
    Registered User
    Join Date
    May 2010
    Location
    Naypyidaw
    Posts
    1,314
    Here's also a way to handle cleaning up. Handling Allocation Errors - Essays - Projects - Conman Laboratories Of course using goto =)

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 9
    Last Post: 03-20-2009, 05:22 PM
  2. Coding Guideline ....!!
    By imfeelingfortun in forum Tech Board
    Replies: 8
    Last Post: 10-08-2006, 07:09 AM
  3. Coding Contest....
    By Koshare in forum A Brief History of Cprogramming.com
    Replies: 46
    Last Post: 10-14-2001, 04:32 PM

Tags for this Thread