views:

514

answers:

5

I have an Objective C project incorporating a C file with some helper functions. I have a grave and very irritating problem trying to return floats from the C file.

C file:

float returnFloat() {
    return 10.0;
}

Meanwhile in an Objective C instance method:

float x;
x = returnFloat();

x is always 0.000000. Any ideas what I'm doing wrong?

Edit

OK, I've realised I have a bunch of "implicit declaration" warnings in the Objective C file, relating to use of the functions I have in the C file.

Assignments using functions that return ints are working fine. Where an assignment is made from a function returning a float, the debugger says "variable optimized away by compiler".

Is it likely I'm not using the "correct" way to include a C file containing helper functions in an Objective C project? I have (stupidly?) just let Xcode link it in automagically. Even if so, why should this problem manifest only when the function is returning a float?

A: 

It's cause you want:

// the c way
float returnFloat() {
   return 10.0;
}

float result = returnFloat();

// the objective-c way
- (float) returnFloat {
   return 10.0;
}

float result = [self returnFloat]; // assuming this is an object

Not what you have. You're mixing C function prototypes with Objective-C. Try the C way mentioned above (Should be able to use it in Objective-C code).

Sorry if I misunderstood your question, I'm pretty sure my code is correct :)

EDIT: Clarification for all of the downvoters. In his first revision of the post he made it float returnFloat {} instead of float returnFloat() { }, which prompted my answer.

EDIT 2: Apparently that wasn't clear enough. In his first revision of his post, he was mixing the C way of writing function prototypes with the Objective-C way of writing function prototypes. You CAN use C functions in Objective-C, but you CAN'T mix the way of writing their function prototypes, as I explained above. Sorry for any confusion.

Jorge Israel Peña
Are you sure? My understanding is that you can intersperse C and Objective C, although it's not necessarily recommended. Calling C functions from Objective C shouldn't be a problem, surely?
Benji XVI
No yeah, sorry, I reworded my answer. You CAN include C and C++ code in Objective-C programs, but what you were doing was mixing the SYNTAX. You were mixing the C way of writing function prototypes with the objective-c way. Sorry if it sounded confusing at first :)
Jorge Israel Peña
Reason for the down vote?
Jorge Israel Peña
I wasn't making things up as I went along. Look at his post edit. He originally had it as float returnFloat { }, not float returnFloat() { }, simple misunderstanding.
Jorge Israel Peña
Have slightly reworded the question to make plain that the second code snippet is from *within* an instance method, rather than trying to *be* one.
Benji XVI
Just to be perfectly clear, *every* C function is a valid Objective C function, and you call it exactly as you would in normal C code.
Stephen Canon
Yes, Stephen, but I mean he was mixing the way of writing the C function prototypes with the way of writing the Objective-C prototypes. But it turned out that that was a typo.
Jorge Israel Peña
A: 

How are you determining that x is 0.0000? A common mistake in debugging is to use the wrong format string in NSLog().

If you are, using NSLog(), make sure you're using the %f or some variant of it:

NSLog(@"x = %f", x);

(many people get mixed up and try to use %i instead)

EDIT: That's with the assumption that your C function prototype is correct and the lack of parentheses was just a typo here. If not, Blaenk's answer is likely correct.

Matt Ball
Am definitely using the %f flag, have tried in both sprintf and NSLog.
Benji XVI
The lack of parentheses was indeed a typo in the question and is not a problem in the actual code.
Benji XVI
Yeah, the lack of parenthesis was logically the first thing to look at. Instead people decided to downvote me and accuse me of making things up as I go along, hah.
Jorge Israel Peña
Not your fault Blaenk. Apologies for the stupid typos.
Benji XVI
Not your fault either, typos are common accidents, it's NSD who accused me of making things up and downvoted me. Hope your question gets answered cause it's really intriguing and mysterious!
Jorge Israel Peña
+10  A: 

You have to use a .h file, just like with .m files, to declare what you're doing in another file. So, you need something like this for this scenario (these are incomplete):

returnfloat.c

float returnFloat() {
    return 10.0;
}

returnfloat.h

float returnFloat(void);

usefloat.m

#import "returnfloat.h"

- (void) someMethod {
    float ten = returnFloat();
}

The problem (given away by your "implicit declaration" warnings) is that the compiler is assuming that you are calling something that returns an int or id, not a float. When you work with C, things need to be prototyped (GCC will treat the .c file like C, and all C rules apply, even though you're in an Objective-C project).


If you'd like to see an example, here's something from one of my projects -- production code (you can write pure C in a file ending in .m, and GCC will treat it like Objective-C in some ways):

DebugF.m

#import "DebugF.h"

void __Debug(const char *file, int line, NSString *format, ...) {
#ifdef DEBUG
    /* Wraps NSLog() with printf() style semantics */
#endif
}

DebugF.h

#ifndef __DEBUGF_H_INCLUDED__
#define __DEBUGF_H_INCLUDED__

#ifdef DEBUG
#define DebugF(args...) __Debug(__FILE__, __LINE__, args)
#else
#define DebugF(...)
#endif /* DEBUG */

void __Debug(const char *file, int line, NSString *fmt, ...);

#endif /* __DEBUGF_H_INCLUDED */

SomeViewController.m

DebugF(@"Got these arguments: %u, %@, %@", 4, anObject, [anObject somethingElse]);
Jed Smith
+1; Jed's got your answer.
Carl Norum
You should include 'returnfloat.h' in 'returnfloat.c' so that the function definition is checked against the function declaration. Further, in general, 'returnfloat.c' should include 'returnfloat.h' as the first, if not only, header - so that you can be confident it is self-contained.
Jonathan Leffler
Thank you, very much. A part of me has been searching for that information for months, not knowing how exactly to phrase the question!
Benji XVI
@Jonathan: Second example is more complete and demonstrates this, first example has an emphasis on brevity.
Jed Smith
@Jed: And I've just noticed you work for Linode, the best webhost, period. It's been an honour!
Benji XVI
+1  A: 

I'm no Objective-C programmer, but in C world the compiler assumes int return type for any undeclared function that current module uses. It looks to me that creating a normal C header file containing:


#ifndef _MY_IMPORTANT_HEADER_
#define _MY_IMPORTANT_HEADER_
extern float returnFloat();
#endif

and including that into your .m file should make it all work:


#include "myheader.h"
Nikolai N Fetissov
A: 

How did you declare 'returnFloat()' to your Objective-C program? Does it have a prototype in scope? If not, then your likely problem is that Objective-C is treating the function as returning an int, not a float, and havoc ensues (or you perceive that zero is returned).

Jonathan Leffler