CFNumber macro for constants - ios

Pretty sure the answer is No on this one, but it's painful enough I have to ask: Is there a CFNumber equivalent to CFString's CFSTR macro? To avoid this sort of thing:
char one = 1;
CFNumberRef cfONE = CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &one);
if (cfONE != NULL) {
... finally I can compare something to the number 1! ...
CFRelease(cfONE);
} else {
// not likely, but possible, if you really want to be conservative
}
Note that I'm not using Objective-C in this particular code.
Eric

If you plan on using this function multiple times, you could the static modifier and stop worrying about deallocation:
static CFNumberRef cfONE = NULL;
if (cfONE == NULL) {
static char one = 1;
cfONE = CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &one);
assert (cfONE != NULL); // Oh no, destroy the world!
}
// ... finally I can compare something to the number 1! ...
So long as you have static, the static analyzer will leave you alone on the leak issue since it is an expected constant size memory allocation, O(1) rather than O(n) where n is the number of executions.
There are several ways to make this a macro. I came up with this lazy one:
#define CFNUMDEF(name, type, numberType, value) \
static CFNumberRef name = NULL; \
if ( name == NULL) { \
static type val = value ;\
name = CFNumberCreate(kCFAllocatorDefault, numberType , &val);\
assert ( name != NULL); \
}
CFNUMDEF(cfONE, char, kCFNumberCharType, 1);
// ... finally I can compare something to the number 1! ...

CFSTR is a little different from your case
CFSTR() allows creation of compile-time constant CFStringRefs; the argument
should be a constant C-string.
CFSTR(), not being a "Copy" or "Create" function, does not return a new
reference for you. So, you should not release the return value. This is
much like constant C or Pascal strings --- when you use "hello world"
in a program, you do not free it.
Where as the object you create with CFNumberCreate will be owned by the caller so you may still want to keep the word create in the name to make this clear.
You could always make a helper function just to avoid passing the same arguments over and over
CFNumberRef PSNumberCreateWithChar(x)
{
return CFNumberCreate(kCFAllocatorDefault, kCFNumberCharType, &x);
}

CFNumberRef and NSNumber are toll free bridged so you can use the NSNumber literal syntax and cast the result.

Related

ExpandEnvironmentStringsA() String Subscript out of range

I have a Function which checks to see if IIS is installed and gets the installation path.
int IsIISInstalled(string &pathname)
{
DWORD returnvalue;
long keyres = RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\InetStp\\", 0, KEY_READ, &miva);
if (keyres == ERROR_SUCCESS)
{
char szBuffer[512];
DWORD dwBufferSize = sizeof(szBuffer);
ULONG nError;
nError = RegQueryValueExA(miva, "InstallPath", NULL, NULL, (LPBYTE)szBuffer, &dwBufferSize);
if (nError == ERROR_SUCCESS)
{
char retBuffer[512];
DWORD nsize = sizeof(retBuffer);
returnvalue = ExpandEnvironmentStringsA(szBuffer, retBuffer, nsize);
pathname = retBuffer;
}
}
if (!pathname.empty())
return 1;
else
return 0;
}
When i attach to my executable and debug this there is a return value from ExpandEnvironmentStringsA
in retBuffer showing the installation path. returnvalue shows 28 as is the TCHARS that was put in the buffer. Once i step into the next line setting the string pathname to the retBuffer it fails giving me a string subscript out of range. I understand what that error means, i have done it plenty of times. What is odd to me is if i specify a new string var in the function:
string fakeresult;
and set fakeresult to retBuffer:
fakeresult = retBuffer;
just as i am in the code above it passes through just fine with no errors. I am calling the function with this code.
string iis_path, miva_path;
int disable;
char *full_path;
//getMivaLocation(miva_path);
bool good2go;
int iisinstalled, empressaReturn, miaReturn;
iisinstalled = IsIISInstalled(iis_path);
Does this have to do with the fact i am passing pathname by reference to the function?
If that is the case why?
How could i fix this to be able to return my data?
I am not a well educated c++ coder i am learning a lot of this as i go and have learned much from you guys. Hoping someone has an idea on this as i do not wish to spend much more time researching to no avail. Thanks.
After stepping into further i found that the pathname is being set as it should. It is immediately crashing on the next call to another functions so my debugging was incorrect. Now i have scoped further hopefully i can fix this. Also for my own note, the reason why it would not crash when i set fakestring instead of pathname was due to the fact i was passing pathname in the function call that is crashing. With no value it is not setting something out of its scope.

Passing an object that undergoes default argument promotion to 'va_start'

This is my first Xcode app and objective-c so give me some slack :)
I tried googling on the issue but I cannot see any help regarding Xcode and app development. I added the error masseages after //
- (id)initWithBytes:(int8_t)byte1, ... { //Error: 1. Parameter of type 'int8_t' (aka 'signed char') is declared here
va_list args;
va_start(args, byte1); //Error: Passing an object that undergoes default argument promotion to 'va_start' has undefined behavior
unsigned int length = 0;
for (int8_t byte = byte1; byte != -1; byte = va_arg(args, int)) {
length++;
}
va_end(args);
if ((self = [self initWithLength:length]) && (length > 0)) {
va_list args;
va_start(args, byte1); // Error: Passing an object that undergoes default argument promotion to 'va_start' has undefined behavior
int i = 0;
for (int8_t byte = byte1; byte != -1; byte = va_arg(args, int)) {
_array[i++] = byte;
}
va_end(args);
}
return self;
}
Thank you in advance!!
va_start() saves the pointer to the first argument passed to the function into a va_list.
The arguments themselves are passed via a hardware stack.
The issue with int8_t comes from the way the hardware stack is implemented. (in x86 at least)
Just like the SSE and MMX does, the stack requires elements stored on it to have an alignment equal to a multiple of 16bits, so everything passed to the function WILL have at least 16 bits of size, regardless of its type.
But the problem is va_arg() doesn't know about all that. Historically, it was a macro, and all it does is returning a pointer stored in va_list, and incrementing va_list by sizeof(type).
So, when you retrieve the next argument, the pointer returned does not point to the next argument but one byte before it, or not - depending on whether the va_arg is a macro or a compiler built-in function.
And this is what a warning is about.
IMO at least. Pardon my English, It's my 2nd language.

Glib string utility functions (echivalent for strcspn)

I want to extract string that exist after first occurrence of "/"
For example a have a char *card in one of this form:
hw:0/Line
default/Master
and I need char *channel (Line, Master, ...)
In standard C can use "strcspn" and "strlen"
char *card, *channel;
int i;
i = strcspn(card, "/");
if (i == strlen(card)) {
channel = "Master";
} else {
card[i] = 0;
channel = card + i + 1;
}
How can I do this using glib string utility functions?
What's wrong with strcspn and strlen?
GLib reimplements a lot of stuff C99 and POSIX because it targets C89 compilers. It doesn't reimplement things like strlen or strcspn because there is no need to—they are in C89.
GLib also tends to implement UTF-8 versions of a lot of functions, and while there is a g_utf8_strlen I'm not aware of a g_utf8_strcspn I don't think it's really necessary in this case. If it is then you'll probably have to implement it yourself by iterating through the string with g_utf8_next_char and checking against the result of g_utf8_get_char or g_utf8_get_char_validated.

Setting Integer value in Objective c

I have recently started programming in iOS.. I am going through a code snippet that declares the following variables:
int rc = 0X00;
sqlite3_stmt *pStmt = 0X00;
FMStatement *stat = 0X00;
BOOL abc = 0X00;
what does this mean?? I read somewhere that setting 0X00 in a reference variable means setting it to NULL (in C). But what does setting a BOOL type variable and an int type variable to 0X00 mean??
I suggest you read up about the basics of programming languages, specifically, C programing with pointers. Objective-C is a superset of C and follows many similar rules.
But to your question:
The 0x in front of the literal values in the code (0x00) specifies that the value is interpreted as hexadecimal rather than decimal. But 0x00(hex) is the same as 0(dec).
int rc = 0x00; //same as int rc = 0;
int is a primitive type in both Obj-C and C that specifies an integer, effectively you are initializing the variable. In the C language you must initialize variables otherwise they could be pointing at a random piece of memory.
Therefore, examine this code:
int a;
int b = 0;
//a is NOT equal to b!
In C, the variable 'a' has not be initialized and therefore its not typically safe to assume that it will be initialized to 0. Always initialize your variable.
If you did a printf, or an NSLog of the variable 'a' you will see that it prints some huge number and it doesnt make sense (sometimes this is compiler dependent)
The same can be said for a BOOL. Although setting a BOOL to 0 is the same as setting it to false;
BOOL flag = 0; //The same as saying BOOL flag = false;
Now for the final part of your code:
FMStatement *stat = 0X00;
Often in Objective-C if you are dealing with pointers and objects you need to initialise the pointer to point at some memory address. The actual memory address is usually determined by the stack/heap and you don't need to worry about that. But you do need to ensure that the pointer isn't pointing to the wrong location (known as a garbage pointer).
To do this, we simply set our pointer to nil. eg:
FMStatement *stat = nil; //This pointer is now safe. Although memory still hasnt been allocated for it yet
This is usually taken care of for you though when you immediately allocate the memory for an object, therefore in this case you don't need to worry about initializing the pointer to nil:
FMStatement *stat = [[FMStatement alloc]init];
Like I said, I recommend you read about basic C programming, allocations, pointers, datatypes, initialising etc, once you have a grasp of this, then move to Objective-C which then builds ontop of it with Object-Oriented stuff.
Good luck.
0X00 is simply 0 in hexadecimal notation. So,
int rc = 0X00;
is the same as
int rc = 0;
Same for BOOL variables, where 0 is the same as NO. Using 0X00 is odd -- it'd make more sense to use 0 or NO where appropriate, and use nil for the pointers.

Why the need to use enif_compare?

Why does
int enif_compare(ERL_NIF_TERM lhs, ERL_NIF_TERM rhs)
need to be used instead of just
if( lhs == rhs ) return 1;
I believe it matters that I am comparing atoms.
ERL_NIF_TERM is an opaque datatype and, to the best of my knowledge, is more akin to a pointer than a value. In fact, here's the definition: typedef unsigned long ERL_NIF_TERM (technically there are a few variants, but they're all integers with the same size as a memory address on the system)
So, you must use enif_compare for the same reason you must use str_cmp when comparing C strings: the referenced values may be identical, but the values you get are not representative of that.
Consider:
char a[] = "test";
char b[] = "test";
printf("%d\n", a == b);
Logically, you and I know that the strings are identical, but the values a and b are actually pointers to the contained value. So when you do a regular compare (==), it's comparing the pointers, not the underlying value. Since they are distinct values within the function, they are allocated to different memory addresses, and as a result, a != b, but str_cmp(a, b) == true

Resources