Conditional compilation error in objective-c - objective-c

This code isn't working due to Error that I couldn't get which is :
Expected ‘)’
type specifier missing default to ‘int’
Expected parameter declaration
conflicting types or ’NSLog'
this error only appear in line 4
please help thanks,
#import <Foundation/Foundation.h>
#define SYS
#ifdef SYS
NSLog (#"SYS is Define ");
#endif
#define minimum(x,y) (x < y ? x:y)
#define Lower_case(x) ((x>'a') && (x<'z'))
#define ToUper_case(x) ((x-'a')+'A')
#define Uper_case(x) (Lower_case(x) ? (x-'a')+'A':x)
#interface NewDef : NSObject
#end

You have a code statement:
NSLog (#"SYS is Define ");
which is not inside any method/function. This is not allowed in (Objective-)C(++).
You can probably achieve what you wish using:
#pragma message "SYS is Define "
This is a compile-time instruction, just as #define is, to the compiler to (somehow) present a message. In Xcode if this line is reached it will be marked with a warning icon:
If you comment out the #define SYS then the mark will go away as the line is no longer reached:
HTH

Related

Preprocessor macro and BOOL weirdness

Code below yields the output "yes defined", "no defined" and "yes". Why?
#define FOOBAR NO
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
#ifdef YES
NSLog(#"yes defined");
#endif
#ifdef NO
NSLog(#"no defined");
#endif
#if FOOBAR == YES
NSLog(#"yes");
#else
NSLog(#"no");
#endif
// ...
}
YES and NO are not undefined, objc.h defines them as:
typedef signed char BOOL;
#define YES (BOOL)1
#define NO (BOOL)0
What is the value of NO? If it's undefined (like YES), they will both evaluate to 0.
This means your expression is essentially
#if 0 == 0
which is of course true, and thus causes the first call to be compiled.
UPDATE: Not sure how BOOL is defined, but casting to what might be a typedef:ed type is not a very good idea when dealing with the preprocessor. Remember that the the #if is evaluated by the preprocessor, not by the compiler. Read something like this for more information about expressions in the preprocessor. Especially:
The preprocessor does not know anything about types in the language.
All identifieres that the preprocessor doesn't know of are replaced with 0 for evaluation in #if directives. If you don't have defined YES and NO both are 0 (and thus equal).

Code in Objective C 2008 Does not compile

I'm learning the basics of objective-C by Reading 'Objective C For Dummies'.
I'm using XCode 4.4, and I'm trying to get some simple code to work. This question has been posed online before. However - the code doesn't seem to compile with the new version of XCode.
At issue seems to be the line NSLog (#"Here is some amazing text! %i",c); This throws an 'Expected Expression' Error. Per the previous form posting, I have disabled automatic reference checking in preferences and this still fails.
#include <stdio.h>
int main(int argc, const char * argv[])
{
//declare variables
int a;
int b;
int c;
//set the variables
a = 2;
b = 3;
//Perform the computations
c = a % b;
//Output the results
NSLog (#"Here is some amazing text! %c",c);
return 0;
}
Add #import <Foundation/Foundation.h> at the top, and change the NSLog to this:
NSLog (#"Here is some amazing text! %d",c);
Because %c doesn't mean "a variable called c", but rather a char. %d means an int, which is what c is.
You forgot to include the Foundation header:
#import <Foundation/Foundation.h>
Sidenote: The format specifier should be %d.

Objective-C macro to return a string with the function and the line number while accepting a string with a variable number of arguments?

I've found a bunch of macro variations on how to use NSLog as a basis and adding PRETTY_FUNC and LINE but all the variations of those macros simply output the result to the console.
I'd like to have a macro that can take a format with a variable number of arguments, add the name of the method and line number where it was called and then return an NSString but so far, the compiler always complains where I call it. My latest version is as follow:
#define FileLog(format, ...) {\
return [NSString stringWithFormat:#"\n %s [Line %d] \n %#",
__PRETTY_FUNCTION__,
__LINE__,
[NSString stringWithFormat:(format), ##__VA_ARGS__]];\
}
Each time I call it from my code, the compiler generates one of those errors:
error: expected expression before '{' token
I don't want to write a log class or use a framework for that. There must be a way to do that with a macro? Anyone?
Thanks in advance!
This is entirely possible with a macro, I think you just need a little more background on them.
First, macros are not functions, so the braces are unnecessary (and, in fact, are the cause of your error). A macro is really a fairly dumb "copy/paste" that is automated by the preprocessor, using syntax that it understands.
In order to define a macro that spans multiple lines and creates an NSString "in place", you have to escape the newlines with backslashes, like so:
#define FileLog(format, ...) \
[NSString stringWithFormat:#"\n %s [Line %d] \n %#", \
__PRETTY_FUNCTION__, \
__LINE__, \
[NSString stringWithFormat:format, ##__VA_ARGS__]]
Macros do not "return" like a function does, because, as I mentioned, they are merely a way to "copy/paste" text.
You can use it like so:
int num = 42;
NSLog(#"%#", FileLog(#"some number: %d", num));
If you were to look at the preprocessor output (the file that the preprocessor creates before compilation), the above example would expand to something like:
NSLog(#"%#", [NSString stringWithFormat:#"\n %s [Line %d] \n %#", __PRETTY_FUNCTION__, __LINE__, [NSString stringWithFormat:#"some number: %d", num]]);
Try this....
Create an include file
#define LOG_NOLOG_LEVEL 0
#define LOG_ERROR_LEVEL 1
#define LOG_WARN_LEVEL 2
#define LOG_INFO_LEVEL 3
#define LOG_DEBUG_LEVEL 4
#if LOG_HELPER_LEVEL >= LOG_DEBUG_LEVEL
#define LOGDEBUG(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGDEBUG(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_INFO_LEVEL
#define LOGINFO(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGINFO(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_WARN_LEVEL
#define LOGWARN(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGWARN(...)
#endif
#if LOG_HELPER_LEVEL >= LOG_ERROR_LEVEL
#define LOGERROR(...) {[LogHelper log:[NSString stringWithFormat:__VA_ARGS__]];}
#else
#define LOGERROR(...)
#endif
Then create a simple class LogHelper with a single class method as follows....
+ (void) log:(NSString *)message
{
fputs([message cStringUsingEncoding:NSUTF8StringEncoding], stderr);
}
Then in your code, you can put calls like...
LOGDEBUG(#"%s - %d Redirect response received\n%#",__FILE__,
__LINE__,[redirectRequest dumpInfo]);
You can set the LOG_HELPER_LEVEL to the level of logging you want to produce. If you set the level at say LOG_WARN_LEVEL, then no code will be included in your app for INFO or DEBUG levels, so it's easy to package your app up for release.
Hope this helps...
From Viraj Thenuwara, who was my iOS Senior developer who trained me :-)
This macro is much more simpler in its definition and also its usage, than the things mentioned above.
#define debug 1
#if debug
#define AppLog(fmt, ...) NSLog((#"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define AppLog(...)
#endif
And it's usage is as follows:
NSString *url = #"http://google.com";
AppLog(#"url %# and id %d", url, 5);
This AppLog line will print out it's given content only if the debug constant is equal to 1. At the Production time or in anytime you don't want to print the log lines you can disable it by turning that 1 into 0.
And it's console out put will be seen as follows:
Hope this will be helpful to someone else!
Cheers!

Using constant to declare an array of item

Is it possible to use some thing like this in Objective-C:
#define number_of_items 10
and then using it as:
int arr[number_of_items];
Yes, assuming you mean Objective C. It's pretty much a superset of "proper" C so this is perfectly okay. It's also okay in both C and C++.
You can see that it works in the following transcript:
pax> cat qq.m
#import <objc/Object.h>
// First method.
#define number_of_items 10
int arr[number_of_items];
// Second method.
#define NUMBER_OF_ROWS 10
#interface test : Object{ int xyzzy[NUMBER_OF_ROWS]; }
#end;
pax> vi qq.m ; gcc -o qq.o -c qq.m -lobjc
pax> # no errors occurred
And, now that we've finally seen what you're actually using:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define NUMBER_OF_ROWS_ (IS_IPAD? 18: 18)
NUMBER_OF_ROWS_ is not a constant, since it depends on the return value of the function UI_USER_INTERFACE_IDIOM().
In other words, it cannot be calculated at compile time. That's why you're getting the error. You can see this by compiling the following code:
#define IS_IPAD (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
#define NUMBER_OF_ROWS_ (IS_IPAD ? 18: 20)
int UI_USER_INTERFACE_IDIOM(void) {return 20;}
int UIUserInterfaceIdiomPad;
int main (void) {
int arr[NUMBER_OF_ROWS_];
return 0;
}
Under gcc --pedantic, you get:
qq.m: In function ‘main’:
qq.m:8: warning: ISO C90 forbids variable length array ‘arr’
You either need to use a dynamically adjustable collection like NSMutableArray or use an array of the maximum size desired and only use what you need of that.

Why can I not use my constant in the switch - case statement in Objective-C ? [error = Expression is not an integer constant expression]

So I have an issue with using a constant variable in the following switch statement in Objective-C.
I have Constants.h with the following:
// Constants.h
extern NSInteger const TXT_NAME;
And Constants.m as:
// Constants.m
#import "Constants.h"
NSInteger const TXT_NAME = 1;
Then in TabBasic.m I am trying to use this constant in a switch-case statement:
// TabBasic.m
#import "TabBasic.h"
#import "Constants.h"
... code ...
- (IBAction)saveValue:(id)sender {
if ([sender isKindOfClass: [UITextField class]]) {
UITextField *txtField = (UITextField *) sender;
switch (txtField.tag) {
case TXT_NAME:
NSLog(#"Set property name to: %#", txtField.text);
break;
}
}
}
But unfortunately it is giving me the following two errors on the "case TXT_NAME:" line:
Expression is not an integer constant expression
Case label does not reduce to an integer constant
Does anyone know what I'm doing wrong? The "tag" variable of a UITextField returns an NSInteger, so I don't see the issue...
Thanks for your help!
Quick solution, you should place NSInteger const TXT_NAME = 1; in Constants.h, and don't need anything in Constants.m.
Reason: If you set the value of the constant in the .m, it is not visible by other translation units that only include the .h file. The value of the constant must be known at compile time to be able to be used in a case within a switch.
Update:
The above works when compiling in Objective-C++. You need to have your files end in .mm instead of .m for them to be compiled in Objective-C++ instead of Objective-C.
In order to work in Objective-C, you should define your constant either like this:
#define TXT_NAME 1
Or even better, like this:
enum {TXT_NAME = 1};
I would normally follow what Apple seem to do and define a typedef enum in the .h file like this.
typedef NS_ENUM(NSInteger, PSOption) {
PSOption1,
PSOption2,
PSOption3,
PSOption4,
};
You can then use it in your case statement and even pass it into functions as well as a type e.g.
- (void)myMethod:(PSOption)option;
A further advantage of doing this over a #define is code completion and compiler checking