I am using SWIG to generate a PHP extension that calls into a 'c' shared lib. I am able to get most things to work except the following situation...
In my 'c' code I declare a function as (Please note that structure and function names have been changed to protect the innocent):
int getAllThePortInfo(EthernetPort *ports);
In this case, the parameter ports is actually an array of EthernetPort structures. In another 'c' program, I could have called it like this...
EthernetPort ports[4];
int rval = getAllThePortInfo(ports);
<etc>
<etc>
This works fine. Then I run SWIG, generate my shared lib, and all builds well. I get php code that I can call...
$ports = new_ethernetport();
$rval = getAllThePortInfo($ports);
This causes PHP to throw the following error : php: free(): invalid pointer: 0x099cb610
So, I tried to do something like...
$ports = array(new_ethernetport(), new_ethernetport(), new_ethernetport(), new_ethernetport());
$rval = getAllThePortInfo($ports);
But then PHP complained...
PHP Fatal error: Type error in argument 1 of getAllThePortInfo. Expected SWIGTYPE_p_EthernetPort
What I think is happening is that PHP (and SWIG) do not differentiate between pointers and arrays, and in the wrapper, it is thinking 'pointer to a single structure', when, in reality, it is an array of structures.
Is there something in PHP I can do? Allocate a chunk of memory that I can use as a space to store more than one structure?
Is there something with SWIG I can do to make my wrapper understand my intentions better?
I truly would appreciate any suggestions. Thanks.
carrays.i indeed hold the answer to my question...
In the SWIG interface file, I have the following lines...
%include <carrays.i>
%array_functions(EthernetPort, ethernetPortArray);
%include "my_lib.h"
"my_lib.h" contains the typedef for the EthernetPort structure, as well as the function declaration...
#define NUM_ETHERNET_PORTS 4
typedef struct {
int number;
mode_t mode;
} EthernetPort;
int getAllThePortInfo(EthernetPort *ports);
After running SWIG and building the shared lib my_lib.so, I can use the following PHP code...
$ports = new_ethernetPortArray(NUM_ETHERNET_PORTS);
$rval = getAllThePortInfo($ports);
$port0 = ethernetPortArray_getitem($ports, 0);
$pnum = ethernetport_number_get($port1);
$pmode = ethernetport_mode_get($port1);
// port1 port2 port3 etc etc
delete_ethernetPortArray($ports);
The php functions new_ethernetPortArray, ethernetPortArray_getitem, ethernetport_number_get, ethernetport_mode_get, delete_ethernetPortArray were all created by SWIG based on the .i file.
The other benefit SWIG enables is the use of #define's in my php code (e.g. NUM_ETHERNET_PORTS), allowing me a single place for some of my common data. I like that. :-)
Cheers.
#DoranKatt, your solution worked for me too with one minor tweak. I had to change the order in the swig file:
%include <carrays.i>
%include "my_lib.h"
%array_functions(EthernetPort, ethernetPortArray);
with the original order I found it generated code that did not compile because the array functions referred to a type that was included later in "my_lib.h". Of course my code used different names and types but I've kept the original authors names for clarity.
Thanks for posting the original question and answer. This has dug me out of a hole. I couldn't find anything about this in the swig documentation.
Related
I'm using Swig to wrap a third-party C library and load it as a shared PHP extension.
I'm having issues invoking a wrapped function, the error is:
Type error in argument 2 of func_name. Expected SWIGTYPE_p_p_double in [...]
I tried reading the related parts of Swig documentation and as much examples as I could find, but not knowing C I still have a lot of doubts.
I'd like to know how to map to a php type an argument declared as:
double const *const *inputs
Said function has this signature in the library header file (library.h):
int func_name(int size,
double const *const *inputs,
double const *options,
double *const *outputs);
Swig interface (library.i)
%module module_name
%include "carrays.i"
%array_functions(double, doubleArray);
%{
#include "library.h"
%}
%include "library.h"
I can see that Swig defined, in the generated library_wrap.c file, the type reported in the error:
/* -------- TYPES TABLE (BEGIN) -------- */
[...]
#define SWIGTYPE_p_p_double swig_types[6]
[...]
If these parts are not enough, I can surely provide the steps to reproduce it.
I'm not doing it right away because I'm pretty sure that the problem is only in my lack of understanding, so I'm hoping that you could put me towards the right direction.
EDIT 1
Adding some info as requested.
Unluckily I think that my php code is far from the answers, being as simple as:
$data_in = new_doubleArray(2); // surely wrong
doubleArray_setitem($data_in, 0, 5);
doubleArray_setitem($data_in, 0, 10);
$options = new_doubleArray(1);
$out = new_doubleArray(1); // surely wrong, too
func_name(10, $in, $options, $out)
To my understanding $in and $out should be arrays of arrays, here I'm using new_doubleArray() just because it's what I managed to do in order to correctly invoke another function, which takes an array of double as an argument.
Note: I edited library.i too, adding carrays inclusion and doubleArray definition, previously omitted as I thought it was out of scope.
I have a very big array stored in memory after reading a whole file in an array (as hex) like this :
$bin_content = fread(fopen($filename,"r"),filesize($filename));
$hex_decode = explode(" ",chunk_split(bin2hex($bin_content),2," "));
unset($bin_content);
function myfunction($i) {
global $hex_decode;
// stuff here
}
When I create a function that uses this $hex_decode array as global ... the script runs like forever (very slow) but if i call that function passing the $hex_decode as a parameter ( myfunction($i,$hex_decode) instead of myfunction($i) in which $i is a pointer) , things are more faster .
Can anyone explain why ? And is there any way to speed the script by reading that file in a different method .
I need to have the whole file in that array rather that line by line , because I'm building a custom ASN.1 decoder and i need to have it all .
And is there any way to speed the script by reading that file in a different method .
Personally I'd use a stream filter to chunk-read and convert the file as it was read rather than reading the entire file in one go, and then converting and fixing with the entire file in memory, handling any filtering and fixing of the ASN.1 structure within the stream filter.
I know this isn't a direct response to the actual question, but rather to the single quote above; but it could provide a less memory-hungry alternative.
There already was a similar question at StackOverflow, please take a look at:
The advantage / disadvantage between global variables and function parameters in PHP?
If your files can be huge you could consider a memory-conservative approach. ASN.1 is usually encoded in structures of type-length-value, which means that you don't have to store the whole thing in memory, just the data that you need to process at any given time.
Please consider the following code snippet:
From php-5.3.1/ext/session/session.c:
PHPAPI char *php_session_create_id(PS_CREATE_SID_ARGS)
…
gettimeofday(&tv, NULL);
…
/* maximum 15+19+19+10 bytes */
spprintf(&buf, 0, "%.15s%ld%ld%0.8F", remote_addr ?
remote_addr : "", tv.tv_sec, (long int)tv.tv_usec,
php_combined_lcg(TSRMLS_C) * 10);
…
return buf;
}
I have found it on the internet. But I can't understand what code is this. I guess this is the implementation of a php function in C++. If yes, then please explain me how php calles c++ function in it?
The shocking truth is that PHP is written in C. You are looking at the source of PHP itself, or need to explain the question further.
It is not a C++ code, it is pure C. The PHP library can call C functions just like any other library implemented in C. The code snippet generates a "unique" session ID consisting of the client address, the current time, and a pseudo-random number from some linear congruential generator.
I am guessing that you ended up to that piece of code via the DEFCON 18: How I Met Your Girlfriend lecture? Great talk btw. :-)
Now about the code snippet, it is C and it is part of PHP's code. This exact function handles the generation of PHP session ids. You have the entire function logic explained in the lecture i mentioned above, in case you didn't see it.
As a side not, PHP does not call C functions, instead you call a PHP library function and so it happens that most of those functions are written in C and exposed through PHP. On the other hand php_session_create_id does not have an equivalent exposed to PHP, since that one is used internally by PHP when you start a session using PHP session api.
Target is to have something like:
#define sum( f1, f2 ) ( f1 + f2 )
where
sum(2,2)
is 4 in PHP. Is that somehow possible? Even better would be if I could call:
$s = 'first';
APPEND ' and second';
when append will be defined as function/method/something else which is appending to $s so after those 2 lines $s would be 'first and second'.
The point of macros in C is that they are expanded at compile time.
Therefore, using the macros does not have an impact on the speed of your code, which a function doing the same would have.
Therefore, an example of usage is:
#define MYPRINTF(x) printf("MYPRINTF says : %s\n",x)
MYPRINTF("blah");
The code above will be translated by the compiler directly into:
printf("MYPRINTF says : %s\n","blah");
The whole point of it is that it is faster than defining a function, such as this one:
void myprintf(char *x)
{
printf("myprintf says : %s\n","blah");
}
Because there is no overhead (in a function, you need to push arguments to the stack, etc).
In an interpreted language, like PHP, the above doesn't hold, as everything is executed directly during run-time, therefore using a mechanism like C's #define would be absolutely useless -- therefore, to answer your question, simply use ordinary functions instead.
just a thought from your comments
function withVeryLongWroteByAnIdiot() {
....
}
function xFunc() {
return withVeryLongWroteByAnIdiot();
}
PHP doesn't support macros in this sense, the (really quite valid) argument I believe being that there's not much difference between this and a normal function in PHP.
After all, it's not like there's any value in having a concept like this in a run-time interpreted language.
I don't believe PHP supports macros. If you think about it, macros in C aren't fancy constants, rather constants are the world's most boring C macros. PHP only understands the boring form through the define function.
That said, I disagree with the other respondents about their validity. There is a valid reason for them: when you want to use built-in functions to preprocess something. For example:
macro default_if_empty_value(value, default) (empty(value) ? default : value)
If you try to write that as a function and call it:
default_if_empty_value($this->that['something']->or[$other], 'Not here.');
then you'll get a PHP warning if any part of that variable chain is not defined, and the expanded version is harder to read:
empty($this->that['something']->or[$other]) ? 'Not here.' : $this->that['something']->or[$other];
PHP code is compiled, but it is compiled at runtime. A macro like this would be expanded by the PHP interpreter and then compiled into PHP bytecode. This bytecode is often cached by the PHP interpreter or an add-on like APC.
Hey there, quick question here. I'm sure there's a simple answer.
Coming from PHP, I'm used to declaring a function with a default argument value like this:
function myFunction ($array, $sort = FALSE) {
}
I the sort parameter wasn't filled, the function would continue with the default value of false. In Obj-C, is there a similar thing?
I'm working through the exercises in my "Programming In Objective-C 2.0" book, and it wants me to re-write a fraction class print function to default-ly not reduce the fraction, but if the value TRUE for reduce is given, go ahead and reduce the fraction, then print. The chapter (Nor nowhere in the book) gives any information on this.
Thanks for your help guys :D
Default arguments don't exist in Objective-C, per se. They can't really, because the argument count is inextricably tied to the method name — each colon corresponds to one argument.
Objective-C programmers accomplish a similar goal, though, by creating "convenience" methods that just call to a more "primitive" method with some of the arguments filled in with default values. For example, -[NSArray indexOfObject:] could be implemented as version of -[NSArray indexOfObject:inRange:] with an argument of NSMakeRange(0, [self count]) for the inRange: part.
In this case, though, I don't think your book is talking about that. I think it simply means to reduce the fraction if YES is given for the reduce: argument and not reduce it if NO is given.
There are two standard patterns for achieving what you want.
(1) write a many argument form of a method and then provide fewer argument convenience versions. For example, consider the following methods on NSString:
- (NSComparisonResult)compare:(NSString *)string;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask
range:(NSRange)compareRange;
- (NSComparisonResult)compare:(NSString *)string options:(NSStringCompareOptions)mask
range:(NSRange)compareRange locale:(id)locale;
The first three are conceptually [and likely concretely, I didn't check] implemented as calls through to the fourth version. That, is -compare: calls -compare:options:range:locale: with appropriate default values for the three additional arguments.
(2) The other pattern is to implement the many argument version of the method and provide default values when an argument is NULL/nil or set to some value that indicates the default is desired. NSData has methods that are implemented with this pattern. For example:
+ (id)dataWithContentsOfFile:(NSString *)path options:(NSDataReadingOptions)readOptionsMask
error:(NSError **)errorPtr;
If you pass 0 for the readOptionsMask argument, the NSData will read the contents of the file using an internally defined default configuration. That default configuration may change over time.
This question is super old, but in case anyone finds it, the Objective-C version of the PHP code (assuming this is inside a class) would probably be something like this:
-(id)myFunction:(NSArray*)array {
return [self myFunction:array withSort:FALSE];
}
-(id)myFunction:(NSArray*)array withSort:(BOOL)useSort {
// CODE
}
I used (id)s as there is no data type information in your PHP code. Replacing the (id)s with actual data types would be wise.
Terrible necro but for anyone googling this, Xcode 4.5 supports (via Clang) overloading of C functions with __attribute__((overloadable)).
Overloaded functions are allowed to have different numbers of arguments, so if C functions are appropriate for what you're trying to do you can use that to get default argument values.
Here's a contrived example of an .h file with two functions, both called PrintNum:
// Prints a number in the decimal base
__attribute__((overloadable)) extern void PrintNum(NSNumber *number);
// Prints a number in the specified base
__attribute__((overloadable)) extern void PrintNum(NSNumber *number, NSUInteger base);
and in the .m file:
__attribute__((overloadable))
void PrintNum(NSNumber *number) {
PrintNum(number, 10);
}
__attribute__((overloadable))
void PrintNum(NSNumber *number, NSUInteger base) {
// ...
}
Note that the attribute must be specified in all definitions and declarations of the function.
No, default arguments are a feature of C++, not C or Objective-C.
What you would have to do in objective-c is the following (using your psuedo code above):
function myFunction ($array, $sort)
function myFunction ($array)
// call myFunction($array, FALSE)
You can easily achieve the same effect using #define.
The function in your header file:
+(NSDate*)getDateFromYear:(NSUInteger)year month:(NSUInteger)month day:(NSUInteger)day;
Add a #define for parameter function in header file:
#define GetDateFromYearOnly(year) [YourClassName getDateFromYear:year month:1 day:1]
Then your can use the function like:
NSDate* 2015Date = GetDateFromYearOnly(2015);
And you will get an NSDate object with date 2015/01/01.
If the function is not static, build a new function like this:
-(NSDate*)GetDateFromYearOnly:(NSUInteger)year;
And call:
[self getDateFromYear:year month:1 day:1]