Link to home
Start Free TrialLog in
Avatar of ogeikem
ogeikem

asked on

Perfectly written c code wont compile

Please help...I've got a perfectly written C code which compiles and runs on Digital Mars C Compiler. However, it doesn't run on quincy 99 (http://csjava.occ.cccd.edu/~gilberts/quincy99.html). Can anyone please tell me why?

I have pasted the code below.
Avatar of ogeikem
ogeikem

ASKER

#include <stdio.h>
#include <math.h> /* required for sin() and cos() */
#include <stdlib.h> /* required for random() */

//#define pi 3.14159265358979323846264 /*macro text replacement*/
#define pi 3.14
#define G 9.81
#define DELTA 0.01

  int global_distance;
  float global_velocity;
  int global_angle;
/* these global variables are used to pass data from the main function to the simulate
function */

double last_iteration_x0;
double last_iteration_y0;
double last_iteration_t;
/* these global variables are used to store x0, y0 and t values, before the next iteration

made y0 negative */


double simulate (double x0, double y0, double vx, double vy);

int main()
 {
  int i;
  int distance;
  float velocity;
  int angle;

srand( (unsigned)time( NULL ) );  /* ensures that random number is not fixed  */

       printf("Calculating random distance between 60 meters and 120 meters\n");

distance=random(121);  /* generates random number between 0 and 120  */

  while (distance<60 | distance>120)  /* ensures that random number is between 60 and 120  */
{

  distance=random(121);
}

  printf("Distance = %d meters\n", distance);

double v2=sqrt(distance*G);

 printf("\n");
 printf("Calculating random velocity between %2.1f m/sec and %2.1f m/sec\n",v2, v2+20 );

velocity=random(v2+21);  /* generates random number between 0 and sqrt(distance)*G + 20  */


  while (velocity<v2 | velocity>v2+20)  
/* ensures that random number is between sqrt(distance)*G and sqrt(distance)*G + 20 */
{
 
  velocity=random(121);
}

 printf("Velocity = %2.1f m/sec\n", velocity);


 printf("\n");
 printf("This program has calculated a distance of %d meters and a velocity of %2.1f m/sec\n", distance, velocity);
      global_distance = distance;  
global_velocity = velocity;

 printf("\n");
  printf("Guess an angle between 0 AND 90 degrees ");
scanf(" %d", &angle);     /* Ampersand required */
 
  while (angle<0 | angle>90)  /* ensures that random number is between 60 and 120  */
{
   printf("Wrong angle\n");
 printf("\n");
  printf("Guess an angle between 0 AND 90 degrees ");
  scanf(" %d", &angle);     /* Ampersand required */
}

  global_angle = angle;

 printf("You have entered an angle of %d degrees \n", angle);


double x_velocity = cos(angle * pi/180 )*velocity;
double x_position = (x_velocity*0) - distance;
double y_velocity = sin(angle * pi/180 )*velocity;
double y_position = y_velocity*0 - 0.5*G*pow(0,2);


double l = simulate (x_position, y_position, x_velocity, y_velocity);


char guess[2];
//guess[2] is char array holds the y or n value

 printf("\n");
if (l>0)
  printf("The ball flew long by %2.0f meters\n", l);
if (l<0)
  printf("The ball flew short by %2.0f meters\n", l);
  printf("Would you like to guess again? (y/n) \n");
  printf("Enter y for YES or n for NO ");
  scanf(" %s", guess);
 

while (guess[0]!=121 & guess[0]!=110)
// 121 is the unicode representation of y
// 110 is the unicode representation of n

{
  printf("\n");
  printf("Please enter y or n ");
  scanf(" %s", guess);

}

while (guess[0]==121) // while guess = YES
{

 if (l>10 | l<-10)

{
 printf("\n");
  printf("Enter another angle between 0 AND 90 degrees ");
  scanf(" %d", &angle);     /* Ampersand required */
 
  while (angle<0 | angle>90)  /* ensures that random number is between 60 and 120  */
{
   printf("Wrong angle\n");
 printf("\n");
  printf("Enter an angle between 0 AND 90 degrees ");
  scanf(" %d", &angle);     /* Ampersand required */
}

  global_angle = angle;

 printf("You have entered an angle of %d degrees \n", angle);


x_velocity = cos(angle * pi/180 )*velocity;
x_position = - (distance);
y_velocity = sin(angle * pi/180 )*velocity;
y_position = 0;


l = simulate (x_position, y_position, x_velocity, y_velocity);

if (l<=10 & l>=-10)
break;

printf("\n");
if (l>0)
  printf("The ball flew long by %2.0f meters\n", l);
if (l<0)
  printf("The ball flew short by %2.0f meters\n", l);

}

printf("\n");
  printf("Would you like to guess again? (y/n) \n");
  printf("Enter y for YES or n for NO ");
  scanf(" %s", guess);
}

if (l<=10 & l>=-10)
{
printf("\n");
printf("Congratulations: good angle!\n");
if (l>0)
  printf("The ball flew long by %2.0f meters\n", l);
if (l<0)
  printf("The ball flew short by %2.0f meters\n", l);
  printf("This is within ten meters of the plate\n");
double C_angle1 = (180.0/pi) * 0.5 * asin(global_distance*G/pow(global_velocity,2));
double C_angle2 = 90 - C_angle1;
printf("The calculated angles are %2.2f degrees and %2.2f degrees \n", C_angle1, C_angle2);
printf("\n");
//break;
}


if (guess[0]==110) // while guess = NO
{
printf("\n");
printf("Goodbye!\n");
double C_angle1 = (180.0/pi) * 0.5 * asin(global_distance*G/pow(global_velocity,2));
double C_angle2 = 90 - C_angle1;
printf("The calculated angles are %2.2f degrees and %2.2f degrees \n", C_angle1, C_angle2);

}


   return 0;  /* Always best to do this */ }


double simulate (double x0, double y0, double vx, double vy)

{

  int a; // loop counter1
  int b=0; // loop counter2

  double t=0; // time starts at 0


  for (a=0; a<700; a++)
  {
 

  if (y0 < 0) // loop until y0 becomes negative
{
  printf("Time = %2.2f seconds ", last_iteration_t);

  printf("x_position = %2.2f meters  ", last_iteration_x0);

  printf("y_position = %2.2f meters  ", last_iteration_y0);

  printf("\n");

  break; // stop the iteration
}

  last_iteration_t=t;
  last_iteration_x0=x0;
  last_iteration_y0=y0;


 if (a==b)  
 {

 b = b+100;

  printf("Time = %2.2f seconds ", t);

  printf("x_position = %2.2f meters  ", x0);

  printf("y_position = %2.2f meters  ", y0);

  printf("\n");


 }


vx = cos(global_angle * pi/180 )*global_velocity;
x0 = (vx*t) - global_distance;
vy = sin(global_angle * pi/180 )*global_velocity;
y0 = (vy*t) - (0.5*G*pow(t,2));


  t = t+DELTA;


  }
return last_iteration_x0;

}
Avatar of ogeikem

ASKER

The code generates the following error on quincy 99

c:\ify5.cpp.c: In function `main':
c:\ify5.cpp.c:47: parse error before `double'
c:\ify5.cpp.c:50: `v2' undeclared (first use in this function)
c:\ify5.cpp.c:50: (Each undeclared identifier is reported only once
c:\ify5.cpp.c:50: for each function it appears in.)
c:\ify5.cpp.c:87: parse error before `double'
c:\ify5.cpp.c:100: `l' undeclared (first use in this function)
c:\ify5.cpp.c:106: `guess' undeclared (first use in this function)
c:\ify5.cpp.c:143: `x_velocity' undeclared (first use in this function)
c:\ify5.cpp.c:144: `x_position' undeclared (first use in this function)
c:\ify5.cpp.c:145: `y_velocity' undeclared (first use in this function)
c:\ify5.cpp.c:146: `y_position' undeclared (first use in this function)
c:\ify5.cpp.c:177: parse error before `double'
c:\ify5.cpp.c:179: `C_angle1' undeclared (first use in this function)
c:\ify5.cpp.c:179: `C_angle2' undeclared (first use in this function)
c:\ify5.cpp.c:189: parse error before `double'
I wuldnt call this "perfect" code.
The line:
double v2=sqrt(distance*G);

is using a feature that is in C++ but not in C.

Either rename the file to something.cpp, or use the switch  in the IDE to request C++ semantics.

*OR* you coul djust move the declaration "double v2" up to where the other vars are declared,
then it may compiler a whole lot better as a C program.

BTW how about using 'y' and 'n' instead of their decimal equivalents?




#include <stdio.h>
#include <math.h> /* required for sin() and cos() */
#include <stdlib.h> /* required for random()
//#define pi 3.14159265358979323846264 /*macro text replacement*/
#define pi 3.14
#define G 9.81
#define DELTA 0.01

//#define random random2;
random2(int x)
{
  return rand()%x;
}

int global_distance;
float global_velocity;
int global_angle;
/* these global variables are used to pass data from the main function to the simulate
   function */

double last_iteration_x0;
double last_iteration_y0;
double last_iteration_t;
/* these global variables are used to store x0, y0 and t values, before the next iteration

made y0 negative */


double simulate (double x0, double y0, double vx, double vy);

int main()
{
  int i;
  int distance;
  float velocity;
  int angle;
  double v2;
      double x_velocity;
      double x_position;
      double y_velocity;
      double y_position;
      double l;
        char guess[2];
  srand( (unsigned)time( NULL ) );  /* ensures that random number is not fixed  */

  printf("Calculating random distance between 60 meters and 120 meters\n");
  distance=random2(121);  /* generates random number between 0 and 120  */

  while (distance<60 || distance>120)  /* ensures that random number is between 60 and 120  */
     {

      distance=random2(121);
      }

    printf("Distance = %d meters\n", distance);
 v2=sqrt(distance * G);

  printf("\n");
  printf("Calculating random velocity between %2.1f m/sec and %2.1f m/sec\n",v2, v2+20 );

  velocity=random2(v2+21);  /* generates random number between 0 and sqrt(distance)*G + 20  */


  while (velocity<v2 | velocity>v2+20)  
    /* ensures that random number is between sqrt(distance)*G and sqrt(distance)*G + 20 */
    {

      velocity=random2(121);
    }

  printf("Velocity = %2.1f m/sec\n", velocity);


  printf("\n");
  printf("This program has calculated a distance of %d meters and a velocity of %2.1f m/sec\n", distance, velocity);
  global_distance = distance;  
  global_velocity = velocity;

  printf("\n");
  printf("Guess an angle between 0 AND 90 degrees ");
  scanf(" %d", &angle);     /* Ampersand required */
 
  while (angle<0 | angle>90)  /* ensures that random number is between 60 and 120  */
    {
      printf("Wrong angle\n");
      printf("\n");
      printf("Guess an angle between 0 AND 90 degrees ");
      scanf(" %d", &angle);     /* Ampersand required */
    }

  global_angle = angle;

  printf("You have entered an angle of %d degrees \n", angle);


   x_velocity = cos(angle * pi/180 )*velocity;
   x_position = (x_velocity*0) - distance;
   y_velocity = sin(angle * pi/180 )*velocity;
   y_position = y_velocity*0 - 0.5*G*pow(0,2);


   l = simulate (x_position, y_position, x_velocity, y_velocity);


 
  //guess[2] is char array holds the y or n value

  printf("\n");
  if (l>0)
    printf("The ball flew long by %2.0f meters\n", l);
  if (l<0)
    printf("The ball flew short by %2.0f meters\n", l);
  printf("Would you like to guess again? (y/n) \n");
  printf("Enter y for YES or n for NO ");
  scanf(" %s", guess);
 

  while (guess[0]!=121 & guess[0]!=110)
    // 121 is the unicode representation of y
    // 110 is the unicode representation of n

    {
      printf("\n");
      printf("Please enter y or n ");
      scanf(" %s", guess);

    }

  while (guess[0]==121) // while guess = YES
    {

      if (l>10 | l<-10)

      {
        printf("\n");
        printf("Enter another angle between 0 AND 90 degrees ");
        scanf(" %d", &angle);     /* Ampersand required */
 
        while (angle<0 | angle>90)  /* ensures that random number is between 60 and 120  */
          {
            printf("Wrong angle\n");
            printf("\n");
            printf("Enter an angle between 0 AND 90 degrees ");
            scanf(" %d", &angle);     /* Ampersand required */
          }

        global_angle = angle;

        printf("You have entered an angle of %d degrees \n", angle);


        x_velocity = cos(angle * pi/180 )*velocity;
        x_position = - (distance);
        y_velocity = sin(angle * pi/180 )*velocity;
        y_position = 0;


        l = simulate (x_position, y_position, x_velocity, y_velocity);

        if (l<=10 & l>=-10)
          break;

        printf("\n");
        if (l>0)
          printf("The ball flew long by %2.0f meters\n", l);
        if (l<0)
          printf("The ball flew short by %2.0f meters\n", l);

      }

      printf("\n");
      printf("Would you like to guess again? (y/n) \n");
      printf("Enter y for YES or n for NO ");
      scanf(" %s", guess);
    }

  if (l<=10 & l>=-10)
    {
      double c_angle1;
      double c_angle2;
      printf("\n");
      printf("Congratulations: good angle!\n");
      if (l>0)
      printf("The ball flew long by %2.0f meters\n", l);
      if (l<0)
      printf("The ball flew short by %2.0f meters\n", l);
      printf("This is within ten meters of the plate\n");
      c_angle1 = (180.0/pi) * 0.5 * asin(global_distance*G/pow(global_velocity,2));
      c_angle2 = 90 - c_angle1;
      printf("The calculated angles are %2.2f degrees and %2.2f degrees \n", c_angle1, c_angle2);
      printf("\n");
      //break;
    }


  if (guess[0]==110) // while guess = NO
    {
      double c_angle1;
            double c_angle2;
      printf("\n");
      printf("Goodbye!\n");
      c_angle1 = (180.0/pi) * 0.5 * asin(global_distance*G/pow(global_velocity,2));
      c_angle2 = 90 - c_angle1;
      printf("The calculated angles are %2.2f degrees and %2.2f degrees \n", c_angle1, c_angle2);

    }


  return 0;  /* Always best to do this */ }


double simulate (double x0, double y0, double vx, double vy)

{

  int a; // loop counter1
  int b=0; // loop counter2

  double t=0; // time starts at 0


  for (a=0; a<700; a++)
    {


      if (y0 < 0) // loop until y0 becomes negative
      {
        printf("Time = %2.2f seconds ", last_iteration_t);

        printf("x_position = %2.2f meters  ", last_iteration_x0);

        printf("y_position = %2.2f meters  ", last_iteration_y0);

        printf("\n");

        break; // stop the iteration
      }

      last_iteration_t=t;
      last_iteration_x0=x0;
      last_iteration_y0=y0;


      if (a==b)  
      {

        b = b+100;

        printf("Time = %2.2f seconds ", t);

        printf("x_position = %2.2f meters  ", x0);

        printf("y_position = %2.2f meters  ", y0);

        printf("\n");


      }


      vx = cos(global_angle * pi/180 )*global_velocity;
      x0 = (vx*t) - global_distance;
      vy = sin(global_angle * pi/180 )*global_velocity;
      y0 = (vy*t) - (0.5*G*pow(t,2));


      t = t+DELTA;


    }
  return last_iteration_x0;

}
well this is a bit closer
I don't know about Quincy... but as Qincy uses gcc / g++ I compiled your program in gcc it only gives error in random.... which takes no arguement but you have given some parameter.... so if you modify your random function call then your program works fine......

gcc -lm yourprog.c

works fine..... I think seems correct.... If the error still persists then there might be some setting error in your IDE....

Dennis
ASKER CERTIFIED SOLUTION
Avatar of SaMuEl
SaMuEl

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ogeikem

ASKER

Thanks all.
Thanks.
Oops, I meant to say, variables, instead of methods.  
I think there was too much caffine in that java, I was drinking.
Just for the record, global variables are evil and should be avoided at all costs...

Anyway, its not possible to create "perfect" code. There will always be something you can do better.
Avatar of ogeikem

ASKER

Thanks TheDevo. I'm new to programming and I need all the advice I can get. I'm very interested in reading code so if you have any interesting piece of c or java code you'd like to share, please send it to ogeikem@yahoo.com so that I can have a read.
Just for the record....global variables are NOT "evil and should be avoided at all costs".  :-)

Global variables are like everything else; there's a time and place for them.  If there wasn't, they wouldn't be allowed in the language.  Sometimes using a global variable instead of sending thousands of addresses on the stack as function arguments makes a lot of sense.

Avatar of ogeikem

ASKER

These contradicting pieces of advice are bad for a newbie like me but I agree with kledbetter; global variables have their purpose especially in modular code.
If you have so many addresses to send, it would make more sense to have a "address array structure" with functions that get data from it and put data to it. At this time, I can not think of any good reason to use a global other than functions that can not return a value or take in any parameters. Anything else SHOULD go by the function list.

Additional: Having an "address array structure" also makes more sense from the dynamic memory point of view.
Avatar of ogeikem

ASKER

I think that in languages that are not very modular (like C), data corruption could easily spring up when too many methods (functions) share the same data. However, a modular language like java makes it safer to declare global variables that one or more methods can share.

What kledbetter is saying is that instead of replicating the same data in one or more functions as  function arguments, you can declare these data as global variables that one or more functions can share.
It might be ~safe~

But, that does not make it a good idea. Its probably safe have your arm amputated, but personally I wouldn't get it done. Globals are bad. Its a simple fact that they should be avoided if at all possible. 99.99999999% of the time they serve no purpose being global as opposed to local.
Avatar of ogeikem

ASKER

why replicate reusable variables inside functions when u can declare them as global variables and have all functions share them?
Yeah, just like everything else in the C language, global variable's have a time and a place. They are good when used properly, just like goto :)
There are several reasons:
1) You can not use the CONST keyword in the function definition to prevent data from being changed.
2) Global variables can cause issues with multi-threaded computers.
3) If you start using global variables, you have to start using EXTERN in multi-file programs to allow access to that global variable. (Mostly bug related - IE when you forget)
4) Memory. You only have a fixed amount of memory (Called a stack) available to your program. Local variables only eat up this memory for a short period of time, where as global variables eat up this memory for the entire runtime of the program. In the above example by kledbetter, those 1000 addresses would have to go on the stack using up a massive 4000 bytes. You can't malloc a global variable (as far as I know), but you could make a global variable point to the malloced memory. Note: This is less of an issue on PC's these days, but handheld consoles and mobile phones still have this problem

However, my main reason is that it is very easy to start changing/using global variables by mistake in your functions.This can create bugs in your programs which can take ages to track down. One function that doesn't use global variables can have its inputs and outputs examined, but a function that does make use of a global variable has to have every line examined to ensure the global value hasn't become currupted.

Functions should ideally be "Black Boxes". You put stuff in and you get stuff out. You shouldn't need to know how they work, just their inputs and outputs. Thats why I do not use global variables. Passing in pointers to large data (eg: structures) works better than making that structure global.
Actually, TheDevo I believe global variables aren't stored on the stack, rather they are stored in static storage with the rest of the program.
The stack is only used for temporary variables.
Avatar of ogeikem

ASKER

TheDevo I think we're saying the same thing. I said earlier that in languages that are not very modular (like C), data corruption could easily spring up when too many methods (functions) share the same data.

However, modular languages like java introduce safety mechanisms (like the concept of encapsulation) which makes it safer to declare global variables that one or more methods can share. It also introduces safety mechanisms that allow multiple threads share data safely.

I'd like to know...what is your solution for a situation in C where multiple functions need to share data?

SaMuEl:
Your program is given a fixed amount of memory (The "stack") when it is run. This is decided by the operating system. Your program can not change, move or otherwise increase the size of this memory. This is why we have the malloc library, so that we can dynamically get memory from the OS when we do not have enough space. Global variables go on the bottom of the stack

ogeikem:
Although I am still learning C, I would personally pass every variable I need via the function parameters. For example, part of my current work involves reading in an image file, drawing geometry data on the image file, applying textures and lighting to parts of that file, and then outputtting the image file again.

To achive this, I have used structures to wrap up all my variables. I have a pixelBuffer structure that stores the size of an image file, as well as all its pixels. My main function can call the pixelBuffer_Create( int width, int size ); function, and it returns a POINTER TO a pixelBuffer structure. This allows me to pass the pixelBuffer to any other function with only 4 bytes.

The entire pixelBuffer code (with operator functions) is in a seperate C file. The header file only has the function declairations and the type definitions. The actual implementation of the pixel buffer is hidden from the end user (me), and I can only interact with it via the functions I have written, providing I remember to #include the header file.

I hope this answers both your questions, and that you will be trying to avoid global variables (and goto) where possible
Ugh,
From what I know there are 3 kinds of memory storage in C, possibly 4 depending on how you see it.

Static Storage:
This is where all your program code resides in memory. Your Global variables, and constants, i.e. anything that has a fixed amount of space for the life of the program.

Stack:
This is where temporary variables are pushed/popped on and off, as they go in and out of scope.

Heap:
This is the memory you ask the OS for, i.e. with malloc, it is non contiguous unlike the stack, and static storage. i.e. there is no guarantee that one clump of memory that you've requested will follow the other.

I'm not an expert in C but I'm fairly certain this is how it works. Maybe you'd like to post a question on this matter to see what others say.
:)

P.S. Java doesn't have global variables by the way, well not in the strict sense of the term. You can have data fields which are public, but these technically are not "global variables.
Constants aren't stored, they are copy and pasted in by the compiler during compile time. I'm 99% sure that Static Storage is mearly a part of the stack you can not access. I haven't had much experiance with java since i am studying Computer Games Programming, and java doesn't feature heavily in many games.

Google™ hasn't been overly useful on the stack/static storage issue, so I have made a post on my uni support forums. All of my tutors are ex-industry professionals (Who all tell us globals should be avoided), so hopefully their knowledge will be more extensive than mine.
Avatar of ogeikem

ASKER

Now I get what TheDevo is saying. In java, you can declare global variables by making them public and static. Here is the Code:

 
public class GlobalDataStore {

public static long globalData = 0;

}

Other classes can access variables as GlobalDataStore.globalData. There will be only one value of globalData as it is declared static.

This practice is discouraged in java as it introduces the possibility of data corruption. What I was refering to earlier was declaring variables that are accessible only to the functions within a class. In java, this is accomplished by making such variables private. I guess such variables arent really global in the true sence of the word.

In that case, variables that are really global should be avoided.

Please tell me one thing. In the C language, are the variables declared in the code above really global? The variables I'm refering to are:
int global_distance;
float global_velocity;
int global_angle;

Not really.

Global files are always limited to the .c file that they are in. So, if I had another file called myfunctions, it would not be able to view or use global_distance, global_velocity or global_angle. If you tried to compile the program you would be told that the variables aren't declaired.

However, you can use the "extern" keyword infront of the variable in myfunctions.h ONLY. If you do not add the extern keyword, then you will get compile errors, not to mention the fact your functions won't behave as expected.

--- myfunctions.h ---
extern int global_distance;
extern float global_velocity;
extern int global_angle;

void myFunctionToDoSomethingToTheGlobals( );

--- myfunctions.c ---
#include "myfunctions.h"
void myFunctionToDoSomethingToTheGlobals( )
{
            // Do Something in here //
}

I don't know if you are familiar with multi-file programs, but if not, every file has to be compilled and then they are all linked together. Most command line compilers work like this:
compile main.c myfunctions.c myotherfile.c
Some editors (like MS Visual Studio .NET) will automate this process for you, as well as providing great debugging software.
Okay, here is the official response from my graphical programming tutor, Mr  Tyrone Davison.

--- QUOTE ---
It makes code (esp in multi file programs) very difficult to follow for somebody reading / working on it.  Imagine you are reading thru the code of a function and see a variable used ... hmm, you think, that variable is not a local variable of the function, it is not a parameter passed to the function(, and it is not a member of the current class - if the func is member func) ... so, wtf is it and who set its value and where are not easily answered.  You can have a look at the top of the source file and find 5 #includes each of which could have there own #includes which you would have to track back thru to find out where this damn variable originates and is used ....

so basically, globals suck for readability.

Factor in that that variable can be modified absolutely anywhere in the multitude of files in the project and you got one mother of a mess for debugging.

Don't use globals!  It's bad practice, the equivalent of a professional footballer getting pi**ed and doped up the night before the world cup final in which he is the star player been watched on Sky Sports' player cam by his mother.

T.
--- END OF QUOTE ---

So that pretty much settles the global debate. They should be avoided where possible :-)
 int global_distance;
  float global_velocity;
  int global_angle;
Are all truly global variables, that is to say they can be accessed in other c files, much like your public static data members.

If you were to write
static int global_distance;
static float global_velocity;
static int global_angle;
the scope of these variables would be limited to the current c file.

Note that static here, has a completely different meaning to that of static in Java.
Avatar of ogeikem

ASKER

Thanks for that information. Now I can see some of the subtle differences between C and java.
SaMuEl: I'm sorry but you are mistaken. Global variables are always limited to the file they are in without using the EXTERN keyword. The only other way arround this is to #include a .c file, which is generally a worse idea that using globals in the first place, and defeats the whole point of having two or more files.

 --- QUOTE ---
  int global_distance;
  float global_velocity;
  int global_angle;
Are all truly global variables, that is to say they can be accessed in other c files, much like your public static data members.

If you were to write
static int global_distance;
static float global_velocity;
static int global_angle;
the scope of these variables would be limited to the current c file.

Note that static here, has a completely different meaning to that of static in Java.
--- END QUOTE ---

Assuming that those declairations were made in the same file as your main function:
You could NOT access them in any other file in a multi-file project straight away. Observe:

--- main.c ---
int pointlessGlobalInt;

#include <stdio.h>
#include "myFunction.h"

int main( )
{
     pointlessGlobalInt = 10;
     printf( "Global is %d\n", pointlessGlobalInt );
     myFunction( );
     return 0;
}

--- myFunction.h ---
void myFunction( );

--- myFunction.c ---
#include <stdio.h>
#include "myFunction.h"

void myFunction( )
{
     printf( "Global in another file is %d\n", pointlessGlobalInt );
}
--- End of files ---

If you try to compile those two files into one object, you get:
myFunction.c(6): error C2065: 'pointlessGlobalInt' : undeclared identifier

If you wanted it to work, you would have to add "extern int pointlessGlobalInt;" to either myFunction.c or myFunction.h

[NOTE: I have not used guard conditions to keep the file short. Also, if anyone even thinks about suggesting that you #include "myFunction.c".... well don't.]
TheDevo, you are mistaken.

A global variable has external linkage unless you use the 'static' keyword in its declaration. An object with external linkage will be shared by the whole program. The error you are getting is merely due to the fact that pointlessGlobalInt is not in scope. The Right Thing to do would be to declare it as an "extern int pointlessGlobalInt" in myFunction.c (or myFunction.h). Another possibility is declaring it as an "int pointlessGlobalInt", which would be a tentative definition, which would still work.

To see that there really is one object called "pointlessGlobalInt" in the whole program, you would have to define it more than once (a declaration with an initializer of an object with external scope is a definition), which would give you a linker error. Try:

--- somefile.c ---
int someint = 1;

--- someotherfile.c ---
int someint = 2;

--- End of files ---

Global objects declared without the 'static' keyword have external linkage, but they do not have global scope in every translation unit, since, by definition, every unit is compiled seperately.

So to complete SaMuEl's answer:

"int global_distance;
float global_velocity;
int global_angle;

Are all truly global variables, that is to say they can be accessed in other c files *given that they are given scope (ie declared)*, much like your public static data members."
>> Okay, here is the official response from my graphical programming tutor, Mr  Tyrone Davison.

  [snip]

Ok, I don't know who mister Tyrone Davidson is, but I'm going to put my last 2 cents in on this topic as a professional programmer for 25 years, coding everything from operating systems to hard disk drivers to disk caches to C compilers and cross-assemblers on mainframes, Ataris, Macintoshes, and PC's.  I wrote my first multi-player game, which allowed 300 online players at one time, on a system called PLATO back in 1979 (yes, online games in 1979!  surprising, huh? :).  Nothing to brag about, just to show that I know a little about what I'm talking about.

Anytime anyone ever makes a comment like "xxxx is bad and should NEVER be used", then you should ignore every word they're saying because they're being overdramatic and speaking about something they probably know little about.  Don't you think the folks who designed C and C++ are pretty smart?  Do you think they were sitting around one day, drinking coffee, and one of them says "I know!!  Let's put some STUPID things in our language that are absolutely terrible, and then we'll see if we can trick ignorant programmers into using them!  I know...lessee...a GOTO!  Yea, that's it!  And, how about global variables?  Now that'd be cool!  We'll confuse the hell out of 'em!"

Anyone who knows how the internals of C / C++ compilers work (and, yes, I do) knows that at certain times both global variables and goto's can be a very efficient programming tools, especially if you're optimizing time-critical code.  Should you use them every day?  Absolutely not.  Should you NEVER use them?  Only if you never have a need.

Every commercial program I've ever written has had global variables; anyone who says you should never use globals has never written a large application before.  What I generally do is something like this....

In a defines.h file, I'll define a global struct like this:

typedef struct
{
      short    fieldWhatever;
      long     fieldWhatever2;
          .....
      int       fieldWhateverN;
} GlobalStruct;

then, in my main I'll define:

   GlobalStruct Globals;

then, in any .c or .cpp that needs those fields, I'll

    extern GlobalStruct Globals;

that way, you get the benefit of using global variables when they're needed, plus they're clearly marked as globals and packaged together in one nice, compact structure.  This is incredibly useful for holding things like program options the user has set, state information like where the last window position was when your application was close, etc.

-Keith

ps:  sorry if I sound a bit contrary over this, but I hate to see new programmers being told things they shouldn't be being told :-)
aib_42, you mis-understood my post. I was deliberately posting a program that wouldn't work to show that globals are limited in scope to the file they are declaired in.

kledbetter, I did say that I was a student, and still learning. However, in my 2D games engine I have not yet found a reason to use globals. Possibly in my final year project, but I'm not holding my breath.

Mr Tyrone Davison is an ex c/c++ programmer who know teachs at the university of Teesside. Ex-students have always spoken very highly of him after they've spent years in the computer games industry, so he must be doing something right. If its not evidence enough, Mr Kieth Ditchburn (Programmer on Emperor: Battle for Dune - although he wishes they'd spent more time designing it!) also agrees globals are rarely used.

To reflect on my comments so far, possibly "Avoid like the plague" is a little extreme in huge applications, but you can understand why as students we would be told to avoid them. There is really no use for globals in our work at univeristy.