-2

Why doesn't the following work when using double (it works using int)

test.c

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


int main () {

    printf("L1: %f \n", myGet_L1());

    mySet_L1(10.0);

    printf("L1: %f \n", myGet_L1());

    return 0;
}

myFcn.c

#include "myFcn.h"

double L1 = 0.0;

double get(double *v) {
     return *v;
}

void set(double *variable, double value) {
    *variable = value;
}

myFcn.h

 #ifndef __MYFCN_H__
 #define __MYFCN_H__

 extern double L1;
 #define myGet_L1()                  get(&L1)
 #define mySet_L1(value)             set(&L1, (value))

 #endif

I don't see why this is working when using int but not doubles?

  • 6
    You need function prototypes for `get` and `set` in test.c. – mch Jun 12 '17 at 09:27
  • Why is L1 declared as a global spaghetti variable? Any particular reason it can't be private to myFcn.c? – Lundin Jun 12 '17 at 09:28
  • Get a new compiler! Implicit int function declarations were banned 18 years ago. Why would anyone use a compiler that's so old that it has not been updated during the past 18 years? (In case of gcc older than version 5.0, the issue is often mis-configuration. Use `-std=c11 -pedantic-errors`.) – Lundin Jun 12 '17 at 09:34
  • @Lundin, it can't be private because it is used in the macro-expansion. i.e., test.c:11:25: error: use of undeclared identifier 'L1', ./myFcn.h:7:42: note: expanded from macro 'myGet_L1' – user3502042 Jun 12 '17 at 10:55
  • @user3502042 Yeah why do you use it in the macro expansion for? That's completely superfluous and contradicts private encapsulation. `static double L1 = 0.0; ... double get(void) { return L1; }; ... void set (double value) { L1 = value; }` – Lundin Jun 12 '17 at 11:30

1 Answers1

1

First a comment: enable compiler warnings! That way, you might have found the answer yourself:

Your compilation unit for test.c misses prototypes for your get() and set(), so they're implicitly assumed to be

int get();
int set();

Which means they take an unspecified number of arguments (promoted to int) and return an int. This happens to generate some working code if you really use int for your L1, but doesn't work with double.

Solution: Declare your functions in the header file:

 #ifndef __MYFCN_H__
 #define __MYFCN_H__

 extern double L1;
 double get(double *);
 void set(double *, double);

 #define myGet_L1()                  get(&L1)
 #define mySet_L1(value)             set(&L1, (value))

 #endif

Other notes:

  • With the code you provide, there's on the other hand no reason at all to have the variable itself visible to other compilation units, so better remove the line

     extern double L1;
    
  • identifiers starting with underscores are reserved (see this answer for the complete rules), so the naming of your guard macro is not wise. Just use MYFCN_H instead.

  • 1
    `()` does not mean "unspecified number of `int` arguments", it means "unspecified number of arguments of unspecified types". – unwind Jun 12 '17 at 09:32
  • @unwind: fixed, kind of, I don't feel I should go into too much detail on this here ... –  Jun 12 '17 at 09:34
  • The OP might be using a dinosaur compiler that only conforms to C90. Then enabling warnings might not help them. – Lundin Jun 12 '17 at 09:34
  • @Lundin sure, but is this a realistic assumption? AFAIK, even `msvc` should complain here ... well, I wrote "might" ;) –  Jun 12 '17 at 09:37
  • 1
    There's plenty of dinosaur compilers around. Not only Visual Studio, but various more or less exotic embedded compilers. And then SO does still get questions about completely ancient compilers like Turbo C now and then. – Lundin Jun 12 '17 at 09:43