Argument-array without environment variables? - objective-c

I'm creating a small C-program and would like a char pointer array holding only the arguments the executable was started with.
Currently this code also outputs all environment variables:
int main (int argc, const char * argv[]) {
while(argv) {
NSLog(#"Parameter %s\n", *argv);
argv++;
}
}

Instead of doing the cycle the way you do, use argc. The size of argv array is argc, with the first value argv[0] being how the name of the program being executed.
int main (int argc, const char * argv[]) {
for (int i = 1; i < argc; ++i) {
NSLog(#"Parameter %s\n", argv[i]);
}
}
Your code is also dumping the environment variables because they are supplied as an additional parameter after argv. In fact you are accessing memory out of bounds for argv and it is pure luck this works.

Change while(argv) to while(*argv). That will give you just the arguments.
main() is actually called like this main(int argc, char **argv, char **environ)
What is happening is you are going past argv and into environ. This behavior
is undefined should not be relied on. Your code, as it is, will also keep on going past environ
and won't stop, you'll be printing garbage.
You can, of course, do it the other way:
for(int i = 0; i < argc; i++) {
NSLog(#"Parameter %s\n", argv[i]);
}
argv[0] contains the program name, the rest are the arguments.

Related

functions calling from main method objective c

Here I need to write a function which is called from main method with integer array as a parameter please give me example.
In below example parameter are int type.
Note : please tell this is correct way to do this or not...
#import <Foundation/Foundation.h>
void displayit (int);
int main (int argc, const char * argv[])
{
#autoreleasepool {
int i;
for (i=0; i<5; i++)
{
displayit( i );
}
}
return 0;
}
void displayit (int i)
{
int y = 0;
y += i;
NSLog (#"y + i = %i", y);
}
Thanks in advance....
I tried out these, please check.
#import <Foundation/Foundation.h>
void displayit (int array[], int len);
int main (int argc, const char * argv[])
{
#autoreleasepool {
int array[]={1,2,3};
displayit( array, 3 );
}
return 0;
}
void displayit (int array[], int len)
{
for(int i=0;i<len;i++){
NSLog(#"display %d : %d",i,array[i]);
}
}
The out put is:
2014-10-30 14:09:32.017 OSTEST[32541:77397] display 0 : 1
2014-10-30 14:09:32.018 OSTEST[32541:77397] display 1 : 2
2014-10-30 14:09:32.018 OSTEST[32541:77397] display 2 : 3
Program ended with exit code: 0
I used another parameter len to avoid boundary beyond.
If the array is a global, static, or automatic variable (int array[10];), then sizeof(array)/sizeof(array[0]) works. Quoted From Another Question

Programmatically get all frame variables in objective-c

I'm trying to create my own custom assert. However, I would like my assertion to automatically include all of the relevant variables. This seems really basic to me, and I've searched around for about an hour but I can't seem to find a way get access to all the relevant stack frame variables. Does anyone know how to get these variables?
FYI - I don't need to access the variables in the debugger, I need to access them programmatically. I would like to upload them along with the crash report to give me more information about the crash. I also know that I can print them out manually...that is exactly what I'm looking to avoid.
You are basically asking to re-invent a good sized chunk of the debugger.
Without symbols, there isn't anything you can interrogate to figure out the layout of the local frame. Even with symbols, it is quite likely that the optimizer will have stomped on any local variables as the optimizer will re-use stack slots at whim once it determines the variable is no longer needed within the frame.
Note that many crashes won't be able to be caught at all or, if caught, the frame within which they occurred will have long since been destroyed.
Since you mention that you are creating a custom assertion, it sounds like you really aren't looking to introspect crashes as much as dump a snap of the local frame when you programatically detect that things have gone off the rails. While there really isn't a means of automatically reporting on local stack state, you could do something like:
{ ... some function ....
... local variables ...
#define reportblock ^{ ... code that summarizes locals ... ; return summary; }
YourAssert( cond, "cond gone bad. summary: %#", reportblock());
}
Note that the #define ensures that each YourAssert() captures the state at the time of the assertion. Note also that the above might have a potentially significant impact on performance.
Note also that I just made that code up. It seems like it is worthy of investigation, but may prove non-viable for a number of reasons.
If you're willing to use Objective-C++, then this is definitely a possibility, as long as you are also willing to declare your variables differently, and understand that you will only be able to grab your own variables with this method.
Also note that it will increase your stack frame size with extra __stack_ variables, which could cause memory issues (although I doubt it, personally).
It won't work with certain constructs such as for-loops, but for 95% of cases, this should work for what you need:
#include <vector>
struct stack_variable;
static std::vector<const stack_variable *> stack_variables;
struct stack_variable {
void **_value;
const char *_name;
const char *_type;
const char *_file;
const char *_line;
private:
template<typename T>
stack_variable(const T& value, const char *type, const char *name, const char *file, const char *line) : _value((void **) &value), _type(type), _name(name), _file(file), _line(line) {
add(*this);
}
static inline void add(const stack_variable &var) {
stack_variables.push_back(static_cast<const stack_variable *>(&var));
}
static inline void remove(const stack_variable &var) {
for (auto it = stack_variables.begin(); it != stack_variables.end(); it++) {
if ((*it) == &var) {
stack_variables.erase(it);
return;
}
}
}
public:
template<typename T>
static inline stack_variable create(const T& value, const char *type, const char *name, const char *file, const char *line) {
return stack_variable(value, type, name, file, line);
}
~stack_variable() {
remove(*this);
}
void print() const {
// treat the value as a pointer
printf("%s:%s - %s %s = %p\n", _file, _line, _type, _name, *_value);
}
static void dump_vars() {
for (auto var : stack_variables) {
var->print();
}
}
};
#define __LINE_STR(LINE) #LINE
#define _LINE_STR(LINE) __LINE_STR(LINE)
#define LINE_STR _LINE_STR(__LINE__)
#define LOCAL_VAR(type, name, value)\
type name = value;\
stack_variable __stack_ ## name = stack_variable::create<type>(name, #type, #name, __FILE__, LINE_STR);\
(void) __stack_ ## name;
Example:
int temp() {
LOCAL_VAR(int, i_wont_show, 0);
return i_wont_show;
}
int main(){
LOCAL_VAR(long, l, 15);
LOCAL_VAR(int, x, 192);
LOCAL_VAR(short, y, 256);
temp();
l += 10;
stack_variable::dump_vars();
}
Output (note the junk extra bytes for the values smaller than sizeof(void *), there isn't much I can do about that):
/Users/rross/Documents/TestProj/TestProj/main.mm:672 - long l = 0x19
/Users/rross/Documents/TestProj/TestProj/main.mm:673 - int x = 0x5fbff8b8000000c0
/Users/rross/Documents/TestProj/TestProj/main.mm:674 - short y = 0xd000000010100
Threads will royally screw this up, however, so in a multithreaded environment this is (almost) worthless.
I decided to add this as a separate answer, as it uses the same approach as my other one, but this time with an all ObjC code. Unfortunately, you still have to re-declare all of your stack variables, just like before, but hopefully now it will work better with your existing code-base.
StackVariable.h:
#import <Foundation/Foundation.h>
#define LOCAL_VAR(p_type, p_name, p_value)\
p_type p_name = p_value;\
StackVariable *__stack_ ## p_name = [[StackVariable alloc] initWithPointer:&p_name\
size:sizeof(p_type)\
name:#p_name\
type:#p_type\
file:__FILE__\
line:__LINE__];\
(void) __stack_ ## p_name;
#interface StackVariable : NSObject
-(id) initWithPointer:(void *) ptr
size:(size_t) size
name:(const char *) name
type:(const char *) type
file:(const char *) file
line:(const int) line;
+(NSString *) dump;
#end
StackVariable.m:
#import "StackVariable.h"
static NSMutableArray *stackVariables;
#implementation StackVariable {
void *_ptr;
size_t _size;
const char *_name;
const char *_type;
const char *_file;
int _line;
}
-(id) initWithPointer:(void *)ptr size:(size_t)size name:(const char *)name type:(const char *)type file:(const char *)file line:(int)line
{
if (self = [super init]) {
if (stackVariables == nil) {
stackVariables = [NSMutableArray new];
}
_ptr = ptr;
_size = size;
_name = name;
_type = type;
_file = file;
_line = line;
[stackVariables addObject:[NSValue valueWithNonretainedObject:self]];
}
return self;
}
-(NSString *) description {
NSMutableString *result = [NSMutableString stringWithFormat:#"%s:%d - %s %s = { ", _file, _line, _type, _name];
const uint8_t *bytes = (const uint8 *) _ptr;
for (size_t i = 0; i < _size; i++) {
[result appendFormat:#"%02x ", bytes[i]];
}
[result appendString:#"}"];
return result;
}
+(NSString *) dump {
NSMutableString *result = [NSMutableString new];
for (NSValue *value in stackVariables) {
__weak StackVariable *var = [value nonretainedObjectValue];
[result appendString:[var description]];
[result appendString:#"\n"];
}
return result;
}
-(void) dealloc {
[stackVariables removeObject:[NSValue valueWithNonretainedObject:self]];
}
#end
Example:
#include "StackVariable.h"
int temp() {
LOCAL_VAR(int, i_wont_show, 0);
return i_wont_show;
}
int main(){
LOCAL_VAR(long, l, 15);
LOCAL_VAR(int, x, 192);
LOCAL_VAR(short, y, 256);
temp();
l += 10;
puts([[StackVariable dump] UTF8String]);
}
Output:
/Users/rross/Documents/TestProj/TestProj/main.m:676 - long l = { 19 00 00 00 00 00 00 00 }
/Users/rross/Documents/TestProj/TestProj/main.m:677 - int x = { c0 00 00 00 }
/Users/rross/Documents/TestProj/TestProj/main.m:678 - short y = { 00 01 }
This requires ARC (and all of it's magic) enabled for any file you want to test this in, or you will manually have to release the __stack_ variables, which won't be pretty.
However, it now gives you a hex dump of the variable (rather than the weird pointer one), and if you really tried hard enough (using __builtin_types_compatible), it could detect whether the result was an object, and print that.
Once again, threads will mess this up, but a simple way to fix that would be to create a NSDictionary of NSArrays, with a NSThread as the key. Makes it a bit slower, but let's be honest, if you're using this over the C++ version, you aren't going for performance.

how to pass command line argument in Mac Application

I have created a Command line tool application ( Xocde --> New App --> Command line tool) and its running without any problem,
Now i want to run it through terminal and pass some command line argument, something like this
int main(int argc, const char * argv[])
{
std::cout << "got "<<argc<<" arguments";
for ( int i = 0; i<argc;i++){
std::cout << "argument:"<<i<<"= "<<argv[i];
}
//// some other piece of code
}
if i type on the terminal
>open VisiMacXsltConverter --args fdafsdfasf i am getting output
got 1 argumentsargument:0= /Applications/VisiMacXsltConverte
I want to know through command line what is the way to pass the argument
If you use just one - (hyphen) those values will go into a volatile UserDefaults dictionary (will also override other keys for the life of the process).
./program -Param 4
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSLog(#"param = %#", [[NSUserDefaults standardUserDefaults] valueForKey:#"Param"]);
}
return 0;
}
or you can just pass these in how ever you want and use the following which will give you an NSArray of NSStrings.
[[NSProcessInfo processInfo] arguments];
Why you want to run it with open?
I would run it with (if you have it in you $PATH you should omit the './'):
./VisiMacXsltConverter arg1 arg2 arg3 arg4
Hope I have not misunderstood you question.

simple code with EXC_BAD_ACCESS

I am new to the objective c and i write the code according to a reference book.
but something went wrong and I don't know why.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
if (argc==1){
NSLog(#"you need to provide a file name");
return (1);
}
FILE *wordFile = fopen(argv[1], "r");
char word[100];
while(fgets(word , 100, wordFile)){
word[strlen(word)-1] = '\0';
NSLog(#"the length of the %s is %lu", word, strlen(word));
}
fclose(wordFile);
return 0;
}
the tool indicates that the while part went wrong, EXC_BAD_ACCESS.
Any idea?
It compiles and runs fine on my machine. But imagine you have an empty line in your file. Then strlen(word) will return zero. Hence word[strlen(word)-1] = '\0'; will try to set some memory which might not be valid since word[-1] might not be a valid memory cell, or a memory cell that you can legally access.
Oh, and by the way, it has nothing to do with objective-c. This is mostly (but for the NSLog call) pure ansi C.

Nested functions are disabled; use f-nested functions to re-enable

I am just learning Objective C and I am having great difficulty. This is what is typed and it is giving me an error. I typed the text that is bold. What is wrong with it. It gives me the nested function error right after int main(void)
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [NSAutoreleasePool alloc] init];
// **#include <stdio.h>
int main(void)
int amount = 1000000;
printf("The amount in your account is $%i\n", amount);
return 0;
}**
NSLog(#"Hello, World!");
[pool drain];
return 0;
}
Your problem is that C and it's brethren do not like functions within functions (putting aside gcc extensions for now).
What you seem to be trying to do is to declare a whole new main inside your main. That's a big no-no. What I suspect is that you've cut-and-pasted an entire C program into the middle of your existing main.
Start with:
#import <Foundation/Foundation.h>
#include <stdio.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [NSAutoreleasePool alloc] init];
int amount = 1000000;
printf("The amount in your account is $%i\n", amount);
NSLog(#"Hello, World!");
[pool drain];
return 0;
}
and work your way up from there.