How to get an "extern const int" value by its name - ios

I would like to get the int value of my extern const by its name.
For example in my .h file:
extern const int MY_INT_CONST;
In my .m file:
const int MY_INT_CONST = 0;
What I want:
- (void) method {
int i = [getMyConstantFromString:#"MY_INT_CONST"];
}
How can I do that?
I searched in RunTime api and I did not find anything.

There's no simple way to do this. Neither the language nor the runtime provide a facility for this.
It can be done using the API of the dynamic loader to look up a symbol's address by its name.
// Near top of file
#include <dlfcn.h>
// elsewhere
int* pointer = dlsym(RTLD_SELF, "MY_INT_CONST");
if (pointer)
{
int value = *pointer;
// use value...
}
Note, that's a C-style string that's passed to dlsym(). If you have an NSString, you can use -UTF8String to get a C-style string.

No need for [getMyConstantFromString:#"MY_INT_CONST"];
directly use as follows
- (void) method {
int i = MY_INT_CONST;
}

Related

How to create a table of linker-resolved data in non-dirty memory

I would like to create a table of data, and keep it in non-dirty memory (so that the table doesn't contribute to them memory usage of the app on iOS and related platforms (tvOS/watchOS)).
The table is an array of two pieces of data: Objective-C class and a numeric value:
#include <Foundation/Foundation.h>
struct TypeMap {
Class class;
int value;
};
I'd like to do something like this:
struct TypeMap map [] = {
{ [NSObject class], 0x1234 }
};
but that obviously doesn't work, clang complains with:
test.m:9:4: error: initializer element is not a compile-time constant
{ [NSObject class], 0x1234 }
^~~~~~~~~~~~~~~~
which makes total sense of course, since [NSObject class] is not a compile-time constant.
But there is a symbol that the dynamic loader is able to resolve: _OBJC_CLASS_$_NSObject, which leads me to something like this:
extern Class OBJC_CLASS_$_NSObject;
struct TypeMap map [] = {
{ OBJC_CLASS_$_NSObject, 0x1234 }
};
The idea being that the dynamic linker can resolve the symbol at runtime, and then mark the memory as read-only (the same way it works for normal code).
Unfortunately it runs into the same problem:
test.m:11:4: error: initializer element is not a compile-time constant
{ OBJC_CLASS_$_NSObject, 0x1234 }
^~~~~~~~~~~~~~~~~~~~~
I'm certain I can express this in assembly code, but I'd like to avoid assembly if possible and stick with Objective-C (no need to implement it once per platform).
Am I completely off track here? Is this even possible?
UPDATE
Working version:
// clang test.m -framework Foundation
#include <Foundation/Foundation.h>
#include <objc/objc.h>
#include <objc/runtime.h>
struct TypeMap {
Class class;
int value;
};
extern void* OBJC_CLASS_$_NSObject;
const struct TypeMap map [] = {
{ (Class) &OBJC_CLASS_$_NSObject, 0x1234 },
};
int main ()
{
printf ("%s %p %i\n", class_getName (map[0].class), map [0].class, map [0].value);
return 0;
}
If I understand correctly, a Class in Objective-C is an aggregate type, in the sense in which the C standard uses that term. Then, given
struct TypeMap {
Class class;
int value;
};
extern Class OBJC_CLASS_$_NSObject;
struct TypeMap map [] = {
{ OBJC_CLASS_$_NSObject, 0x1234 }
};
you are asking the dynamic loader to copy the aggregate into your data structure, at load time, which is not a feature that it has.
What you should be able to do instead is have your TypeMap contain pointers to the OBJC_CLASS_$_... symbols:
struct TypeMap {
Class *class;
int value;
};
extern Class OBJC_CLASS_$_NSObject;
const struct TypeMap map[] = {
{ &OBJC_CLASS_$_NSObject, 0x1234 },
// ...
};
Give that a whirl and see how it goes.
(Note the added const on the declaration of map — you need that to get this data structure put in the read-only data segment in the first place.)

Is there a method to allow pure c file to use <Metal/Metah.h>?

In other words, could ios's metal be used in pure c file? Thanks for reviewing.
The Metal API is Objective-C, however that shouldn't present a problem as you can provide C functions within Objective-C implementation files so the rest of your C-based code can call these functions.
For example (I don't know the Metal API, so this is gibberish):
metalapi.h:
// This is a C function...
extern int doThingWithMetal(int someParam, const char *otherParam);
metalapi.m:
#import <Metal/Metal.h>
// ... implemented in Objective-C
int doThingWithMetal(int someParam, const char *otherParam)
{
return [someMetalClass someMethod:someParam] == SOME_VALUE ? 0 : 1;
}
otherfile.c
#include "metalapi.h"
....
if (doThingWithMetal(1, "Hello") == 0) {
...
}

Objective C Macro append to string

I think this is a very simple thing to do, but since I'm new to iOS development and objective C, I can't figure it out.
#define RESTFUL_PATH_PREFIX #"https://gogch.com/gch-restful";
#define LOGIN RESTFUL_PATH_PREFIX #"/login;
I want the result "https://gogch.com/gch-restful/login"
but I'm getting the result as "https://gogch.com/gch-restful"
other topics in stackoverflow mention only about adding a new string to the beginning of a string like,
#define DOMAIN "example.com"
#define SUBDOMAIN "test." DOMAIN
Remove the trailing semi-colon:
#define RESTFUL_PATH_PREFIX #"https://gogch.com/gch-restful";
^
and then string constants can be concatenated by the compiler:
#"first" #"second"
instead of:
#"first"; #"second"
It is much better practice to use constants instead of define macros.
static NSString *const YourPath = #"https://...";
And then you can concatenate your strings with NSString stringWithFormat: method.
Since I made this answer to a question marked as a dupe, I'll also answer it here
Sure, you can use defines OR you can use NSString constants. It's really a matter of preference ... I have however seen both a #define and an NSString const * const being used before. Defines are easier, and you're probably not going to save that much memory by having constants instead of individual immutable instances of NSString all over the place.
Some advice is to think about how you export the NSString constants. You'll probably want EXTERN_PRIVATE instead of EXTERN, but my sample code will allow all clients of your header to read the string constants you've declared therein.
What you can do:
Create a new .m/.c file with a header in Xcode
In the .m/.c file, declare and initialise your constants
Export the constant as necessary so other compilation units can access it
constants.h
#ifndef constants_h
#define constants_h
// Export the symbol to clients of the static object (library)
#define EXTERN extern __attribute__((visibility("default")))
// Export the symbol, but make it available only within the static object
#define EXTERN_PRIVATE extern __attribute__((visibility("hidden")))
// Make the class symbol available to clients
#define EXTERN_CLASS __attribute__((visibility("default")))
// Hide the class symbol from clients
#define EXTERN_CLASS_PRIVATE __attribute__((visibility("hidden")))
#define INLINE static inline
#import <Foundation/Foundation.h>
EXTERN NSString const * _Nonnull const devBaseUrl;
#endif /* constants_h */
constants.m
#include "constants.h"
NSString const * _Nonnull const devBaseUrl = #"http://127.0.0.1:8000/";
main.m
#import <Foundation/Foundation.h>
#import "constants.h"
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSLog(#"Constant value: %#", devBaseUrl);
// Prints: Constant value: http://127.0.0.1:8000/
}
return 0;
}

byte array in arduino library

ok so here is one for you maybe simple but i am not so sure.
i have the following code and it may be clear what i wish to do by looking at the code.
Arduino.ino
RF myRF; //Creation of RF class.
const int dataSize = 500;
byte storedData[dataSize];
//array is populated through program then the following is called
myRF.populate(storedData);
RF.CCP
const int dataSize = 500;
byte recivedData[dataSize];
void RF::populate(byte reciveddata){
recivedData = reciveddata;
}
RF.H
#include Arduino.h
#ifndef RF_H
#define RF_H
class RF {
public:
RF();
~RF();
void recive();
void send();
void print();
void sendnew(byte Storeddata);
};
#endif
this is however producing an error "byte is not declared"
Hope its clear what i intend to do and hope you can help thanks.
There are two problems in your files:
h file:
#include Arduino.h
You should write
#include <Arduino.h>
c file:
const int dataSize = 500;
byte recivedData[dataSize];
void RF::populate(byte reciveddata){
recivedData = reciveddata;
}
Here you have a big problem. You are declaring recivedData here, but you want to assign it a value coming from another part of the program. This is not how it works.
IMO you have two ways to do this.
1) store just the pointer to the memory; this way is faster and occupies less memory than solution 2, but you have to ensure that the storedData variable you pass in the .ino file is not changed during the function
#include "RF.h" // I hope you already included this
byte *recivedData;
void RF::populate(byte *reciveddata){
recivedData = reciveddata;
}
2) copy the content of the received array to this array; this way you have a copy of the array, so you occupy twice the memory (but you can edit storedData without problems).
#include "RF.h" // I hope you already included this
const int dataSize = 500;
byte recivedData[dataSize];
int recivedDataLength;
void RF::populate(byte *reciveddata, int reciveddatalength){
recivedDataLength = (reciveddatalength>dataSize) ? dataSize : reciveddatalength;
for (int i = 0; i < recivedDataLength; i++)
recivedData[i] = reciveddata[i];
}

c programming how to write this in main

You can write the prototypes without the variable names?
int example(examplestruct *var1, examplestruct *var2);
void done(examplestruct *var1,FILE *f);
struct {
int* field1;
int field2;
}examplestruct;
Is it possible to write the prototypes without name variables?
Can anyone tell me if this is acceptable in C language? You can write the prototypes without the variable names?
Yes.
As for the second question:
If you want a function to be inside main(), then take the body of the function, put it in main() and make sure that the arguments that the function had are well handled.
This example will clear things up:
#include <stdio.h>
void print(int);
void inc_p(int);
int main(void) {
int num = 5;
print(num);
inc_p(num);
// to get rid of inc_p(), copy paste it's body inside main
// and you will get this
// a++;
// print(a);
// However, a was an argument, here you need to use
// the variable declared in main(), i.e. 'num'
num++;
print(num);
return 0;
}
void print(int a) {
printf("%d\n", a);
}
void inc_p(int a) {
a++;
print(a);
}

Resources