如何将.a C静态库添加到Xcode并在那里使用它?(How to add .a C static library to Xcode and use it there? [duplicate])
这个问题在这里已有答案:
- 如何在Xcode 4中“添加现有框架”? 9个答案
我有一个用arm7-gcc编译的静态C库,我想在我的iOS项目中使用它。 我把它添加到项目但我无法弄清楚如何使用它。
This question already has an answer here:
I have a static C library compiled with arm7-gcc and i want to use it in my iOS project. i added it to project but i can't figure out how to use it.
原文:https://stackoverflow.com/questions/11830434
最满意答案
首先是一个大警告: “不安全必须死” http://blog.takipi.com/still-unsafe-the-major-bug-in-java-6-that-turned-into-a-java-9-feature/
一些先决条件
static class DataHolder { int i1; int i2; int i3; DataHolder d1; DataHolder d2; public DataHolder(int i1, int i2, int i3, DataHolder dh) { this.i1 = i1; this.i2 = i2; this.i3 = i3; this.d1 = dh; this.d2 = this; } } Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); Unsafe unsafe = (Unsafe) theUnsafe.get(null); DataHolder dh1 = new DataHolder(11, 13, 17, null); DataHolder dh2 = new DataHolder(23, 29, 31, dh1);
基础
要获取字段(i1)的偏移量,可以使用以下代码:
Field fi1 = DataHolder.class.getDeclaredField("i1"); long oi1 = unsafe.objectFieldOffset(fi1);
并且可以访问实例dh1的字段值
System.out.println(unsafe.getInt(dh1, oi1)); // will print 11
您可以使用类似的代码来访问对象引用(d1):
Field fd1 = DataHolder.class.getDeclaredField("d1"); long od1 = unsafe.objectFieldOffset(fd1);
你可以使用它从dh2获取对dh1的引用:
System.out.println(dh1 == unsafe.getObject(dh2, od1)); // will print true
现场排序和对齐
要获取对象的所有声明字段的偏移量:
for (Field f: DataHolder.class.getDeclaredFields()) { if (!Modifier.isStatic(f.getModifiers())) { System.out.println(f.getName()+" "+unsafe.objectFieldOffset(f)); } }
在我的测试中,似乎JVM按其认为合适的方式重新排序字段(即添加字段可以在下次运行时产生完全不同的偏移)
本机内存中的对象地址
重要的是要理解以下代码迟早会使JVM崩溃,因为垃圾收集器会随机移动您的对象,而无法控制何时以及为什么会发生这种情况。
另外,了解以下代码依赖于JVM类型(32位与64位)以及JVM的某些启动参数(即在64位JVM上使用压缩oops)非常重要。
在32位VM上,对对象的引用与int具有相同的大小。 那么如果你调用
int addr = unsafe.getInt(dh2, od1));
你会得到什么? 而不是unsafe.getObject(dh2, od1))
? 它可能是对象的原生地址吗?咱们试试吧:
System.out.println(unsafe.getInt(null, unsafe.getInt(dh2, od1)+oi1));
将按预期打印出
11
。在没有压缩oops的64位VM上(-XX:-UseCompressedOops),您需要编写
System.out.println(unsafe.getInt(null, unsafe.getLong(dh2, od1)+oi1));
在具有压缩oops的64位VM(-XX:+ UseCompressedOops)上,事情有点复杂。 此变体具有32位对象引用,通过将它们乘以8L转换为64位地址:
System.out.println(unsafe.getInt(null, 8L*(0xffffffffL&(dh2, od1)+oi1));
这些访问有什么问题
问题是垃圾收集器和此代码。 垃圾收集器可以随意移动对象。 由于JVM知道它的对象引用(局部变量dh1和dh2,这些对象的字段d1和d2),它可以相应地调整这些引用,你的代码永远不会注意到。
通过将对象引用提取到int / long变量中,可以将这些对象引用转换为原始值,这些原始值恰好具有与对象引用相同的位模式,但垃圾收集器不知道这些是对象引用(它们可能是由也是一个随机发生器),因此在移动物体时不会调整这些值。 因此,一旦触发了垃圾收集周期,您提取的地址就不再有效,并且尝试访问这些地址的内存可能会立即使您的JVM崩溃(好的情况),或者您可能在没有现场注意的情况下丢弃您的内存(坏的)案件)。
First a big warning: “Unsafe must die” http://blog.takipi.com/still-unsafe-the-major-bug-in-java-6-that-turned-into-a-java-9-feature/
Some prerequisites
static class DataHolder { int i1; int i2; int i3; DataHolder d1; DataHolder d2; public DataHolder(int i1, int i2, int i3, DataHolder dh) { this.i1 = i1; this.i2 = i2; this.i3 = i3; this.d1 = dh; this.d2 = this; } } Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); Unsafe unsafe = (Unsafe) theUnsafe.get(null); DataHolder dh1 = new DataHolder(11, 13, 17, null); DataHolder dh2 = new DataHolder(23, 29, 31, dh1);
The basics
To get the offset of a field (i1), you can use the following code:
Field fi1 = DataHolder.class.getDeclaredField("i1"); long oi1 = unsafe.objectFieldOffset(fi1);
and the access the field value of instance dh1 you can write
System.out.println(unsafe.getInt(dh1, oi1)); // will print 11
You can use similar code to access an object reference (d1):
Field fd1 = DataHolder.class.getDeclaredField("d1"); long od1 = unsafe.objectFieldOffset(fd1);
and you can use it to get the reference to dh1 from dh2:
System.out.println(dh1 == unsafe.getObject(dh2, od1)); // will print true
Field ordering and alignment
To get the offsets of all declared fields of a object:
for (Field f: DataHolder.class.getDeclaredFields()) { if (!Modifier.isStatic(f.getModifiers())) { System.out.println(f.getName()+" "+unsafe.objectFieldOffset(f)); } }
On my test it seems that the JVM reorders fields as it sees fit (i.e. adding a field can yield completely different offsets on the next run)
An Objects address in native memory
It's important to understand that the following code is going to crash your JVM sooner or later, because the Garbage Collector will move your objects at random times, without you having any control on when and why it happens.
Also it's important to understand that the following code depends on the JVM type (32 bits versus 64 bits) and on some start parameters for the JVM (namely, usage of compressed oops on 64 bit JVMs).
On a 32 bit VM a reference to an object has the same size as an int. So what do you get if you call
int addr = unsafe.getInt(dh2, od1));
instead ofunsafe.getObject(dh2, od1))
? Could it be the native address of the object?Let's try:
System.out.println(unsafe.getInt(null, unsafe.getInt(dh2, od1)+oi1));
will print out
11
as expected.On a 64 bit VM without compressed oops (-XX:-UseCompressedOops), you will need to write
System.out.println(unsafe.getInt(null, unsafe.getLong(dh2, od1)+oi1));
On a 64 bit VM with compressed oops (-XX:+UseCompressedOops), things are a bit more complicated. This variant has 32 bit object references that are turned into 64 bit addresses by multiplying them with 8L:
System.out.println(unsafe.getInt(null, 8L*(0xffffffffL&(dh2, od1)+oi1));
What is the problem with these accesses
The problem is the Garbage Collector together with this code. The Garbage Collector can move around objects as it pleases. Since the JVM knows about it's object references (the local variables dh1 and dh2, the fields d1 and d2 of these objects) it can adjust these references accordingly, your code will never notice.
By extracting object references into int/long variables you turn these object references into primitive values that happen to have the same bit-pattern as an object reference, but the Garbage Collector does not know that these were object references (they could have been generated by a random generator as well) and therefore does not adjust these values while moving objects around. So as soon as a Garbage Collection cycle is triggered your extracted addresses are no longer valid, and trying to access memory at these addresses might crash your JVM immediately (the good case) or you might trash your memory without noticing on the spot (the bad case).
相关问答
更多-
使用memcpy的垃圾(Trash using memcpy)[2022-06-15]
欢迎使用C ++。 您正在复制您关心的值,但不会复制终止的'\ 0'字符。 假设x有效(即:x> 3且x <= sizeof(缓冲区)),您可以说: output[x - 2] = '\0'; 在调用memcpy()你应该得到你所期望的。 但是:当你处理这样的通信和缓冲时,你需要小心并检查所有内容。 Welcome to C++. You are copying the values you care about but not the terminating '\0' character. Assumi ... -
更快的替代memcpy?(faster alternative to memcpy?)[2022-04-11]
memcpy可能是您可以在内存中复制字节的最快方法。 如果你需要更快的东西 - 试着找出一种不复制东西的方法,例如只交换指针,而不是数据本身。 memcpy is likely to be the fastest way you can copy bytes around in memory. If you need something faster - try figuring out a way of not copying things around, e.g. swap pointers only, ... -
C memcpy相反(C memcpy in reverse)[2022-08-21]
这适用于反向复制int s: void reverse_intcpy(int *restrict dst, const int *restrict src, size_t n) { size_t i; for (i=0; i < n; ++i) dst[n-1-i] = src[i]; } 就像memcpy() , dst和src指向的区域不能重叠。 如果你想在原地逆转: void reverse_ints(int *data, size_t n) { size ... -
使用'memcpy'功能(Using 'memcpy' function)[2023-01-07]
sizeof(a)是数组a的总大小。 例如,在 int a[3]; printf("%d", sizeof(a)); sizeof a在大多数系统上都是12 (因为int通常是4个字节,你有3个)。 memcpy不知道a是一个数组。 它只知道指向一些内存地址,所以你必须告诉它要传递多少字节。 大多数地方都将memcpy的签名描述为: void *memcpy(void *dst, const void *src, size_t nbytes) sizeof(a) is the total size of ... -
strcpy与memcpy(strcpy vs. memcpy)[2023-09-06]
可以做些什么来看这个效果 编译并运行此代码: void dump5(char *str); int main() { char s[5]={'s','a','\0','c','h'}; char membuff[5]; char strbuff[5]; memset(membuff, 0, 5); // init both buffers to nulls memset(strbuff, 0, 5); strcpy(strbuff,s); me ... -
memcpy()vs memmove()(memcpy() vs memmove())[2022-05-21]
我并不完全惊讶,你的例子没有表现出奇怪的行为。 尝试将str1复制到str1+2 ,看看会发生什么。 (实际上可能没有区别,取决于编译器/库)。 一般来说,memcpy是以简单(但是快速的方式)实现的。 简单来说,它只是循环数据(按顺序),从一个位置复制到另一个位置。 这可能会导致源被读取时被覆盖。 Memmove做更多的工作,以确保它正确处理重叠。 编辑: (不幸的是,我找不到体面的例子,但这些会做)。 对比此处显示的memcpy和memmove实现。 memcpy只是循环,而memmove执行测试以确定 ... -
首先是一个大警告: “不安全必须死” http://blog.takipi.com/still-unsafe-the-major-bug-in-java-6-that-turned-into-a-java-9-feature/ 一些先决条件 static class DataHolder { int i1; int i2; int i3; DataHolder d1; DataHolder d2; public DataHolder(int i1, int i ...
-
是否memcpy处理安全?(Is memcpy process-safe?)[2022-10-23]
memcpy通常以原始速度编码。 它不会是线程安全的。 如果你需要这个,你需要在关键部分执行memcpy调用或使用其他的信号机制。 take_mutex(&mutex); memcpy(dst, src, count); yield_mutex(&mutex); memcpy is typically coded for raw speed. It will not be thread safe. If you require this, you need to perform the memcpy ca ... -
有memcpy问题(having memcpy problem)[2024-02-05]
strlen只计算没有终止符'\ 0'的字符。 没有这个终结符printf不知道字符串的结尾。 解决方案:memcpy(s,a,(strlen(a)+1)); strlen does only count the chars without the terminator '\0'. Without this terminator printf does not know the end od the string. Solution: memcpy(s,a,(strlen(a)+1)); -
字符串常量的其余部分被忽略,好像它不在那里。 memcpy一旦达到size字节就会停止。 请注意,尽管将大于size的内存块传递给memcpy是安全的,但传递较短的块会触发未定义的行为。 例如,如果传递少于九个字符的字符串, memcpy会将无效字符复制到字符串末尾之后的myArray 。 The rest of the string constant gets ignored, as if it's not there. memcpy stops as soon as it reaches size by ...