Why argv[] is declared as const? - objective-c

In Objective-C, why argv[] is declared as const:
int main(int argc, const char *argv[]) { }

Because const denotes that the value (char *) is immutable, which arguments are.
Once program arguments are handed off to a program, their values should not be modifiable.
Think of this array as an array of const char *'s, which in turn, is an array of chars.
So, say you passed the string "hello world" to your program as arguments, argv would look like this:
{{'h', 'e', 'l', 'l', 'o', '\0'}, {'w', 'o', 'r', 'l', 'd', '\0'}}

Because it makes writing the shell/program launcher/etc simpler while not making most programs much more complicated.
And the creators of 'C' were thinking ahead to make OS writers jobs easier - especially their own!

Related

What is the C++ CLI equivalent of managed c++'s __typeof and __gc?

I'm trying to convert an old c++ project from VS2003 to VS2019. Part of this, I'm learning, is going from managed C++ to C++ CLI as managed c++ was dropped pretty quickly.
I'm managing for the most part, but I can't seem to figure out what replaces the __typeof keyword. Is there a drop in for this? See below code snippet for context in how it was it's used.
private: System::ComponentModel::IContainer ^ components;
private:
void InitializeComponent(void)
{
this->components = gcnew System::ComponentModel::Container();
System::Resources::ResourceManager ^ resources = gcnew System::Resources::ResourceManager(__typeof(USB::Form1));
.
.
.
}
Additionally, there's another reoccurring identifier, __gc , that I have found some more info on, but am not sure I understand what to replace it with.
Char chars __gc[] = gcnew Char __gc[bytes->Length * 2];
Char hexDigits __gc[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
bool ImageNumberUsed __gc[];
Does anyone have a good grasp on this and know what the proper conversions are given above contexts?
I can't say that I've used much Managed C++, but I can say what the C++/CLI equivalents are.
__typeof(type) --> type::typeid
Access typeid as if it were a static field or property of the given type.
Returns an object of type System::Type^.
Example: gcnew System::Resources::ResourceManager(USB::Form1::typeid);
__gc[] --> class cli::array
cli::array is a full-fledged managed type. You create it with gcnew, variables are declared with the hat ^, etc.
cli::array is generic on the type of object stored in the array, and on the number of dimensions in the array (which defaults to 1). The size of the array is specified via a constructor parameter (using parentheses, not square brackets).
Variables are declared with the name of the type, cli::array. Square brackets are used for reading & writing values, not for declaring the type, nor for creating the array.
If the type inside the array is a managed reference type, you'll need to include the hat ^ inside the generic type. Example: cli::array<String^>^ foo = ...
Examples:
cli::array<System::Char>^ chars = gcnew cli::array<System::Char>(bytes->Length * 2);
cli::array<System::Char>^ hexDigits = { '0', '1', .... };
(I like to say System.Char, as an extra reminder that it's not the same thing as lower-case char.)
cli::array<bool>^ ImageNumberUsed; (Uninitialized or null until assigned)
Two-dimensional: cli::Array<String^, 2>^ stringGrid = gcnew cli::Array<String^, 2>(10, 10);

Different Objective-C enums with the same literals

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.

What is the canonical way to create network packets in Objective C?

Coming from python I could do something like this.
values = (1, 'ab', 2.7)
s = struct.Struct('I 2s f')
packet = s.pack(*values)
I can pack together arbitrary types together very simply with python. What is the standard way to do it in Objective C?
Using a C struct is the normal approach. For example:
typedef struct {
int a;
char foo[2];
float b;
} MyPacket;
Would define a type for an int, 2 characters and a float. You can then interpret those bytes as a byte array for writing:
MyPacket p = {.a = 2, .b = 2.7};
p.foo[0] = 'a';
p.foo[1] = 'b';
char *toWrite = (char *)&p; // a buffer of size sizeof(p)
Not very clear a question, but maybe you're looking for a (packed struct)?
__attribute__((packed)) struct NetworkPacket {
int integer;
char character;
};

How to interpret objective-c type specifier (e.g. returned by method_copyReturnType())?

Given I have a type specifier as returned by method_copyReturnType(). In the GNU runtime delivered with the GCC there are various methods to work with such a type specifier like objc_sizeof_type(), objc_alignof_type() and others.
When using the Apple runtime there are no such methods.
How can I interpret a type specifier string (e.g. get the size of a type) using the Apple runtime without implementing an if/else or case switch for myself?
[update]
I am not able to use the Apple Foundation.
I believe that you're looking for NSGetSizeAndAlignment:
Obtains the actual size and the aligned size of an encoded type.
const char * NSGetSizeAndAlignment (
const char *typePtr,
NSUInteger *sizep,
NSUInteger *alignp
);
Discussion
Obtains the actual size and the aligned size of the first data type represented by typePtr and returns a pointer to the position of the next data type in typePtr.
This is a Foundation function, not part of the base runtime, which is probably why you didn't find it.
UPDATE: Although you didn't initially mention that you're using Cocotron, it is also available there. You can find it in Cocotron's Foundation, in NSObjCRuntime.m.
Obviously, this is much better than rolling your own, since you can trust it to always correctly handle strings generated by its own runtime in the unlikely event that the encoding characters should change.
For some reason, however, it's unable to handle the digit elements of a method signature string (which presumably have something to do with offsets in memory). This improved version, by Mike Ash will do so:
static const char *SizeAndAlignment(const char *str, NSUInteger *sizep, NSUInteger *alignp, int *len)
{
const char *out = NSGetSizeAndAlignment(str, sizep, alignp);
if(len)
*len = out - str;
while(isdigit(*out))
out++;
return out;
}
afaik, you'll need to bake that info into your binary. just create a function which returns the sizeof and alignof in a struct, supports the types you must support, then call that function (or class method) for the info.
The program below shows you that many of the primitives are just one character. So the bulk of the function's implementation could be a switch.
static void test(SEL sel) {
Method method = class_getInstanceMethod([NSString class], sel);
const char* const type = method_copyReturnType(method);
printf("%s : %s\n", NSStringFromSelector(sel).UTF8String, type);
free((void*)type);
}
int main(int argc, char *argv[]) {
#autoreleasepool {
test(#selector(init));
test(#selector(superclass));
test(#selector(isEqual:));
test(#selector(length));
return 0;
}
}
and you could then use this as a starting point:
typedef struct t_pair_alignof_sizeof {
size_t align;
size_t size;
} t_pair_alignof_sizeof;
static t_pair_alignof_sizeof MakeAlignOfSizeOf(size_t align, size_t size) {
t_pair_alignof_sizeof ret = {align, size};
return ret;
}
static t_pair_alignof_sizeof test2(SEL sel) {
Method method = class_getInstanceMethod([NSString class], sel);
const char* const type = method_copyReturnType(method);
const size_t length = strlen(type);
if (1U == length) {
switch (type[0]) {
case '#' :
return MakeAlignOfSizeOf(__alignof__(id), sizeof(id));
case '#' :
return MakeAlignOfSizeOf(__alignof__(Class), sizeof(Class));
case 'c' :
return MakeAlignOfSizeOf(__alignof__(signed char), sizeof(signed char));
...

How to pass a two dimensional array of unknown size as method argument

I'm trying to pass a two-dimensional array, which size can be dynamic, as a method argument.
Within the method I'd like to use the array with the general array syntax.
int item = array[row][column];
To pass the array is not possible, so I thought about to use a pointer pointer.
- (void)doSomethingWithArray:(int **)array columns:(int)nColumns rows:(int)nRows
{
int item = array[n][m];
}
But I get the problem when I try to pass the array as the parameter
int array[numberOfRows][numberOfColumns];
[someObject doSomethingWithArray:array columns:numberOfColumns rows:numberOfRows];
I found a lot of tips & tricks, but somehow nothing really works in the way I would like to use it.
Thanks for help,
Eny
Is objective-c based on C99?
If it is, you can use the "new" syntax that allows you to pass dimension information directly.
#include <stdio.h>
void foo(int rows, int cols, int arr[rows][cols]) {
printf("%d, %d\n", arr[0][0], arr[1][4]);
}
int main(void) {
int arr[2][12] = {{1, 2, 3, 4, 5}, {11, 12, 13, 14, 15}};
foo(2, 12, arr);
}
You can see the code running on ideone.
- (void)doSomethingWithArray:(void *)array columns:(int)nColumns rows:(int)nRows {}
...
[someObject doSomethingWithArray:&array columns:numberOfColumns rows:numberOfRows];