I use this code to set my constants
// Constants.h
extern NSInteger const KNameIndex;
// Constants.m
NSInteger const KNameIndex = 0;
And in a switch statement within a file that imports the Constant.h file I have this:
switch (self.sectionFromParentTable) {
case KNameIndex:
self.types = self.facilityTypes;
break;
...
I get error at compile that read this: "error:case label does not reduce to an integer constant"
Any ideas what might be messed up?
For C/C++ and Objective-C must the case statement have fixed values - "reduced to an integer (read value)" at compile time
Your constants is not a real "constant" because it is a variable and I imagine it can be changed through a pointer - ie &KNameIndex
Usually one defines constants as enum
enum {
KNameIndex = 0,
kAnotherConstant = 42
};
If you would use C++, or Objective-C++ (with .mm as file extension) you could use a const statement as
const int KNameIndex = 0;
You can use
#define KNameIndex 0
...
switch (self.sectionFromParentTable) {
case KNameIndex:
self.types = self.facilityTypes;
break;
...
and it should work.
Just had the same problem and I decided to go with #define rather than enum. Works for me™ ;-)
This is a stab in the dark because I haven't used Cocoa / ObjC in a long time now, but is the member variable sectionFromParentTable not of int type?
I have not worked with Objective C, but I'd try chucking the 'extern'. At least if this were C++, the Constants.m file would not be part of the compilation unit of Other.m, so the value of KNameIndex would be unknown to the compiler. Which would explain the error; an unknowable value can't be a constant.
Does putting the definition, not just the declaration, in the Constants.h file help?
I think you are stuck with using a const int instead of a const NSInteger as switch only works with built in integral types. (not sure about your syntax with const flipped around after the type).
Take a look at the related question: Objective-C switch using objects?
Related
Can you help me avoid this warning: 'kFontFromFontSize' macro redefined
in Gameconfig.h
#ifndef __GAME_CONFIG_H
#define __GAME_CONFIG_H
//
// Supported Autorotations:
// None,
// UIViewController,
// CCDirector
//
#define kFontFromiPaoneToiPad 2.1
#define kFontFromFontSize 2*kFontFromiPaoneToiPad
Your defines seems to work fine when I test using Visual Studio. Are you sure you are not defining these some other place as well? Perhaps your compiler treats it differently. In that case, you can use const globals instead:
const float kFontFromiPaoneToiPad = 2.1;
const float kFontFromFontSize = 2 * kFontFromiPaoneToiPad;
BTW, it is considered a good practice to use parenthesis around compound expressions in #define to avoid any potential problems when it is substituted in your code.
Is there any way to use global int constants in Objective C that work in a case/switch statement? The technique here (http://stackoverflow.com/questions/538996/constants-in-objective-c) lets me access the constants everywhere, but does not let me put them into a switch statement.
in .h
FOUNDATION_EXPORT const int UNIT_IDLE;
FOUNDATION_EXPORT const int UNIT_DEFEND;
in .m
int const UNIT_IDLE = 0;
int const UNIT_DEFEND = 1;
Error is "Expression is not an integer constant expression"
I usually use enumerations with typedef statements when using constants which I will use in a switch statement.
For example, this would be in a shared .h file such as ProjectEnums.h:
enum my_custom_unit
{
MyCustomUnitIdle = 1,
MyCustomUnitDefend = 2
};
typedef enum my_custom_unit MyCustomUnit;
I can then use code similar to the following switch statement in my .c, .m, .cpp files:
#import "ProjectEnums.h"
- (void) useUnit:(MyCustomUnit)unit
{
switch(unit)
{
case MyCustomUnitIdle:
/* do something */
break;
case MyCustomUnitDefend:
/* do something else */
break;
default:
/* do some default thing for unknown unit */
break;
};
return;
};
This also allows the compiler to verify the data being passed to the method and used within the switch statement at compile time.
I think your best option is using enum types. Just declare a type in your header file and then you are ready to use it in a switch statement.
class.h
typedef enum{
kEditGameModeNewGame = 0,
kEditGameModeEdit = 1
}eEditGameMode;
class.m
eEditGameMode mode = kEditGameModeEdit;
switch (mode) {
case kEditGameModeEdit:
// ...
break;
case kEditGameModeNewGame:
// ...
break;
default:
break;
}
Good luck!
Official guideline says you should use "enumerations for groups of related constants that have integer values." That may solve your problem and improve code.
I have a member variable that tells units for a value I have measured like centimeters,kilometers,seconds,hours etc.
Now these are enums,
When I display a corresponding string, I have created a method that returns corresponding string for these enums.
Unlike Java, enums here cant have other properties associated with them.
So I have to explicitly do a if-else-if chain or a switch case to return the correct string.
I am new to Objective C. any good practice that I should be following in such scenarios ?
afaik Objective-C enums are just old-school C enums... so maybe you can use an integer value for them?
I guess if your enum values started at 0 and increased you could use some sort of array access:
const char *distanceUnitToString2(enum DistanceUnit unit)
{
const char *values[] = {
"cm",
"m",
"km"
};
// do some sanity checking here
// ...
return values[unit];
}
But this feels a little flaky to me. What if you have negative values, or you are using bitmask-style enum values like 1 << 8? You are going to end up using a very large array.
You also could use a switch and improve it a little with a macro. Something like this:
const char *distanceUnitToString(enum DistanceUnit unit)
{
#define CASE(UNIT, STRING) case (UNIT): return (STRING)
switch (unit) {
CASE(kCentimeters, "cm");
CASE(kMeters, "m");
CASE(kKiloMeters, "km");
default:
// should not get here
assert(0);
break;
}
#undef CASE
}
But you don't really save that much vs. not using the macro.
Martin James's comment is the right answer. And use a definition of the enum like:
enum units { cm = 0, m, km };
that way you can be sure that your enum translates to the correct index values.
I've been wondering if there's an elegant way to derive a string from an enum in Objective-C or vanilla C. I'm currently using a switch statement like so:
switch (self.requestType)
{
case MSListRequest:
serverRequestType = #"List";
break;
case MSDetailsRequest:
serverRequestType = #"Details";
break;
case MSPurchaseRequest:
serverRequestType = #"PurchaseVolume";
break;
}
I'm curious if there's a cleaner way to derive strings than this.
-edit:
I'm also using the same enum elsewhere to interface to a different system that needs to map the same enums to a different set of strings.
There's no real nice way to do this. A very simple way is to create an array:
NSString *const ENUM_NAMES[] = {
#"List", #"Details", #"PurchaseVolume", ...
};
There are alternatives that use macros and some simple preprocessor hacks to define both the names and the enum itself from the same source. However, the resulting code is more difficult to read.
// some_enum.def
X(List),
X(Details),
X(PurchaseVolume)
// some_enum.h
enum {
#define X(x) x
#include "some_enum.def"
#undef X
};
// some_enum.c
char const *const ENUM_STRING[] = {
#define X(x) #x
#include "some_enum.def"
#undef X
};
I'm not sure of the best way to generate an NSString from the preprocessor, whether you can just stick an # in it or if it's better to use (NSString *)CFSTR(x).
When I need a bunch of code like this, I write a Python script to generate the code from a text file -- it generates GPerf output for converting strings to enum, and it generates the code for converting enum to string as well. Plain old C doesn't do reflection.
The offsetof macro seems not to work under C++/CLI.
This works fine in unmanaged C++, but throws "error C2275: 'Entity' :illegal use of this type as an expression" error in CLI.
struct Property{
char* label;
PropertyTypes type;
unsigned int member_offset;
unsigned int position;
unsigned char bit_offset;
};
struct Entity{
...
bool transparent;
...
};
Property property = {"Transparent",
TYPE_BOOL,
offsetof(Entity, transparent),
0,
0}; // C2275 HERE
Does CLI have some replacement?
My guess would be that the compiler message boils down to: "offsetof" is not a known macro and if it was a function its parameters must not contain a typename.
Edit: As somebody pointed out in the comments, offsetof is actually part of the std lib. So what's missing is probably just
#include <cstddef>
Alternatively, you can use this macro implementation (taken from Win32/MFC headers):
#ifdef _WIN64
#define OFFSET_OF( s, m )\
(size_t)((ptrdiff_t)&reinterpret_cast<const volatile char&>((((s*)0)->m)) )
#else
#define OFFSET_OF( s, m )\
(size_t)&reinterpret_cast<const volatile char&>((((s*)0)->m))
#endif
Standard C++ already has an alternative; &Entity::transparent. You'll probably want to use templates when redesigning the Propery class. The type of a pointer-to-member is non-trivial.
You will need to provide the type of the object you are assigning to. Looks like there is some type-mismatch for the member in question.
See this for sample usage.
Just a shot in the dark and without a chance to double-check this - should
offsetof(Entity, transparent),
perhaps rather read
offsetof( struct Entity, transparent ),
???