I have en error when try to cast own enumerator to address book values:
typedef enum {
kACTextFirstName = kABPersonFirstNameProperty, // error: expression is not an integer constant expression
kACTextLastName = (int)kABPersonLastNameProperty, // error: expression is not an integer constant expression
} ACFieldType;
How to solve the problem?
Thank you.
I need to init my enum using ABAddressBook's framework const values such as kABPersonLastNameProperty or kABPersonFirstNameProperty.
In C (unlike in C++), an object declared const, even if it's initialized with a constant expression, cannot be used as a constant.
You didn't bother to show us the declaration of kABPersonFirstNameProperty, but I"m guessing it's declared something like:
const int kABPersonFirstNameProperty = 42;
If you need to use the name kABPersonFirstNameProperty as a constant expression, you can either declare it as a macro:
#define kABPersonFirstNameProperty 42
or as an enumeration constant:
enum { kABPersonFirstNameProperty = 42 };
Note that the enum hack only lets you declare constants of type int.
Likewise for kABPersonLastNameProperty.
(And why do you cast one of them to int, but not the other?)
If that doesn't answer your question, it's because you didn't give us enough information.
Related
I wish to have two different enums, but they might have the same literal; for example:
typedef enum {ONE,TWO,THREE,FOUR,FIVE,SIX} NumbersEnum;
typedef enum {ONE,TWO,THREE,FIVE,EIGHT} FibonacciEnum;
This will raise a compile error because ONE, TWO, THREE, FIVE are repeated in both enums.
Is there a way to make this work as-is (not changing the literals' names or adding a prefix or suffix)?
Is there any way my code using the literals can look like this: int num = NumbersEnum.SIX; and not like this int num = SIX;?
No. That's part of the C and Objective-C language from the beginning of time. You're not going to change it, and nobody is going to change it for you.
You cannot do this with enums; their members are global and the names must be unique. There is, however, a neat technique you can use to make pseudo-namespaces for constants with structs.
Declare your "namespace" in the appropriate header:
extern const struct _FibonacciNumbers
{
int one;
int two;
int three;
int five;
} FibonacciNumbers;
Then initialize the values in an implementation file:
const struct _FibonacciNumbers FibonacciNumbers = {
.one = 1,
.two = 2,
.three = 3,
.five = 5
};
You now access a constant as, e.g., FibonacciNumbers.one, and other struct types can use the same names since the names are private to each of them.
So that's "No" for your first option, but "Yes" to the second.
I have a question about enum : when I create an enum, does the latest value will always be higher than the first value of the enum ?
Maybe an exemple will be helpful to understand what I mean :
Imagine I am developing a RPG game, in which there are weapons. Each weapon has a type :
typedef enum
{
WoodenSword,
IronSword,
SteelSword,
GoldenSword
}WeaponType;
Now I want to check the difference of power between the weapons (supposing the WoodenSword is the weakest weapon and the GoldenSword is the strongest weapon). Is it possible de check the power of a weapon doing a simple :
WeaponType type = GoldenSword;
if(type > WoodenSword)
{
//Do something
}
In other words, I don't want this but is it possible for an enum value to be like this (if you don't force the value) :
typedef enum
{
WoodenSword, //-> equals 40
IronSword, //-> equals 0
SteelSword, //-> equals 42
GoldenSword //-> equals 5
}WeaponType;
Or it will be this way by default :
typedef enum
{
WoodenSword, //-> equals 0
IronSword, //-> equals 1
SteelSword, //-> equals 2
GoldenSword //-> equals 3
}WeaponType;
Hope to be clear enough. Please, feel free to tell me if I am not precise enough.
Thanks.
For C:
From the C99 standard section 6.7.2.2 Enumeration specifiers:
The identifiers in an enumerator list are declared as constants that have type int and may appear wherever such are permitted.98) An enumerator with = defines its enumeration constant as the value of the constant expression. If the first enumerator has no =, the value of its enumeration constant is 0. Each subsequent enumerator with no = defines its enumeration constant as the value of the constant expression obtained by adding 1 to the value of the previous enumeration constant. (The use of enumerators with = may produce enumeration constants with values that duplicate other values in the same enumeration.) The enumerators of an enumeration are also known as its members.
So, if the value of an enum enumerator is not explicitly set it is guaranteed to be one greater than the previous value.
C/C++ guarantees that if you don't force values, any next non-forced value in enum will be previous + 1.
Yes, the default behavior is how you describe. To get the other behavior, you need to set values like this:
typedef enum
{
WoodenSword = 40, //-> equals 40
IronSword = 0, //-> equals 0
SteelSword = 42, //-> equals 42
GoldenSword = 5 //-> equals 5
} WeaponType;
If you don't force subsequent values you can rely on it, unless ...
root#debian:/home/david# cat demo.c
#include <stdio.h>
#include <limits.h>
enum {a = INT_MAX, b};
int main(void)
{
printf("a=%d b=%d\n", a, b);
return 0;
}
root#debian:/home/david# clang -o demo demo.c
demo.c:4:20: warning: overflow in enumeration value
enum {a = INT_MAX, b};
^
1 warning generated.
root#debian:/home/david# ./demo
a=2147483647 b=-2147483648
Or just use defines instead of enumaration
#define IronSword 0
#define GoldenSword 5
#define WoodenSword 40
#define SteelSword 42
and
if(type > WoodenSword)
{
//Do something
}
When declaring a block what's the rationale behind using this syntax (i.e. surrounding brackets and caret on the left)?
(^myBlock)
For example:
int (^myBlock)(int) = ^(int num) {
return num * multiplier;
};
C BLOCKS: Syntax and Usage
Variables pointing to blocks take on the exact same syntax as variables pointing to functions, except * is substituted for ^. For example, this is a function pointer to a function taking an int and returning a float:
float (*myfuncptr)(int);
and this is a block pointer to a block taking an int and returning a float:
float (^myblockptr)(int);
As with function pointers, you'll likely want to typedef those types, as it can get relatively hairy otherwise. For example, a pointer to a block returning a block taking a block would be something like void (^(^myblockptr)(void (^)()))();, which is nigh impossible to read. A simple typedef later, and it's much simpler:
typedef void (^Block)();
Block (^myblockptr)(Block);
Declaring blocks themselves is where we get into the unknown, as it doesn't really look like C, although they resemble function declarations. Let's start with the basics:
myvar1 = ^ returntype (type arg1, type arg2, and so on) {
block contents;
like in a function;
return returnvalue;
};
This defines a block literal (from after = to and including }), explicitly mentions its return type, an argument list, the block body, a return statement, and assigns this literal to the variable myvar1.
A literal is a value that can be built at compile-time. An integer literal (The 3 in int a = 3;) and a string literal (The "foobar" in const char *b = "foobar";) are other examples of literals. The fact that a block declaration is a literal is important later when we get into memory management.
Finding a return statement in a block like this is vexing to some. Does it return from the enclosing function, you may ask? No, it returns a value that can be used by the caller of the block. See 'Calling blocks'. Note: If the block has multiple return statements, they must return the same type.
Finally, some parts of a block declaration are optional. These are:
The argument list. If the block takes no arguments, the argument list can be skipped entirely.
Examples:
myblock1 = ^ int (void) { return 3; }; // may be written as:
myblock2 = ^ int { return 3; }
The return type. If the block has no return statement, void is assumed. If the block has a return statement, the return type is inferred from it. This means you can almost always just skip the return type from the declaration, except in cases where it might be ambiguous.
Examples:
myblock3 = ^ void { printf("Hello.\n"); }; // may be written as:
myblock4 = ^ { printf("Hello.\n"); };
// Both succeed ONLY if myblock5 and myblock6 are of type int(^)(void)
myblock5 = ^ int { return 3; }; // can be written as:
myblock6 = ^ { return 3; };
source: http://thirdcog.eu/pwcblocks/
I think the rationale is that it looks like a function pointer:
void (*foo)(int);
Which should be familiar to any C programmer.
enum {
ValidationLoginFailed=2000,
ValidationSessionTokenExpired=2001,
ValidationSessionTokenInvalid=2002,
ValidationEmailNotFound=2003
ValidationSucccesMIN=ValidationLoginFailed,
ValidationSucccesMAX=ValidationEmailNotFound,
ValdationValidSuccessCode=9999,
ValdationInvalidCode=10000
};
typedef int ValidationStatusCodes;
please help me out.
In your code, ValidationStatusCodes means int, not your anonymous enum type. So they aren't actually connected in any way.
However, since your enum contains int values, you could say that there's some sort of relation. You can pass the names of the enumerated values and they will be considered of the int or ValidationStatusCodes type.
By the way, Apple does something similar to what you do, except they typedef their collective names to NSInteger or NSUInteger instead of int or uint. See this question for an example.
With all that said, a more common practice is to typedef your custom type name directly to the anonymous enum, like this:
typedef enum {
ValidationLoginFailed = 2000,
ValidationSessionTokenExpired = 2001,
ValidationSessionTokenInvalid = 2002,
ValidationEmailNotFound = 2003
ValidationSuccessMIN = ValidationLoginFailed,
ValidationSuccessMAX = ValidationEmailNotFound,
ValdationValidSuccessCode = 9999,
ValdationInvalidCode = 10000
} ValidationStatusCodes;
if the variable in object_getIvar is a basic data type (eg. float, int, bool) how do I get the value as the function returns a pointer (id) according to the documentation. I've tried casting to an int, int* but when I try to get that to NSLog, I get error about an incompatible pointer type.
Getting:
myFloat = 2.34f;
float myFloatValue;
object_getInstanceVariable(self, "myFloat", (void*)&myFloatValue);
NSLog(#"%f", myFloatValue);
Outputs:
2.340000
Setting:
float newValue = 2.34f;
unsigned int addr = (unsigned int)&newValue;
object_setInstanceVariable(self, "myFloat", *(float**)addr);
NSLog(#"%f", myFloat);
Outputs:
2.340000
For ARC:
Inspired by this answer: object_getIvar fails to read the value of BOOL iVar.
You have to cast function call for object_getIvar to get basic-type ivars.
typedef int (*XYIntGetVariableFunction)(id object, const char* variableName);
XYIntGetVariableFunction intVariableFunction = (XYIntGetVariableFunction)object_getIvar;
int result = intVariableFunction(object, intVarName);
I have made a small useful macro for fast definition of such function pointers:
#define GET_IVAR_OF_TYPE_DEFININTION(type, capitalized_type) \
typedef type (*XY ## capitalized_type ## GetVariableFunctionType)(id object, Ivar ivar); \
XY ## capitalized_type ## GetVariableFunctionType XY ## capitalized_type ## GetVariableFunction = (XY ## capitalized_type ## GetVariableFunctionType)object_getIvar;
Then, for basic types you need to specify calls to macro (params e.g. (long long, LongLong) will fit):
GET_IVAR_OF_TYPE_DEFININTION(int, Int)
And after that a function for receiving int(or specified) variable type become available:
int result = XYIntGetVariableFunction(object, variableName)
The value that is returned is the value from the right place in the object; just not the right type. For int and BOOL (but not float), you could just cast the pointer to an int or BOOL, since pointers and ints are the same size and they can be cast to each other:
(int)object_getIvar(obj, myIntVar)
It's probably boxing the value in an NSNumber. You can verify this by NSLogging the returned id's className, like so:
id returnedValue = object_getIvar(self, myIntVar);
NSLog(#"Class: %#", [returnedValue className]);
Edit: I found another question just like this one here: Handling the return value of object_getIvar(id object, Ivar ivar)
From my own experimentation, it would appear that my original assumption was incorrect. int and float and other primitives appear to be returned as the actual value. However, it would be appropriate to use ivar_getTypeEncoding to verify that the returned value is the type that you're expecting it to be.
you can use object_getInstanceVariable directly: (haven't tested it)
void *ptr_to_result;
object_getInstanceVariable(obj, "intvarname", &ptr_to_result);
float result = *(float *)ptr_to_result;