Block_copy的实现(32位机器)

本文详细介绍了Block在Objective-C中的实现细节,包括Block的结构体组成、不同类型的Block及其转换方式,以及局部变量的存储方式等内容。此外还探讨了如何通过Block_descriptor中的copy_helper函数对引用变量进行retain或copy操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

此函数声明和相关的结构体如下

void Block_copy(struct block_literal_generic block);

struct block_literal_generic {
    void *isa;      // 可能为NSGlobalBlock,NSStackBlock,NSMallocBlock
    int flags;   // 内存块属性,决定了Block_copy的行为,
    int reserved;   // 网上说是是当前block引用计数
    void (*invoke)(void *, ...); // block函数地址
    struct Block_descriptor {
        unsigned long int reserved; 
        unsigned long int size; // _block_literal_generic占用大小
        void (*copy_helper)(void *dst, void *src); // 对引用的变量进行retain或copy操作
        void (*dispose_helper)(void *src); 
    } descriptor;
    // 紧挨着存放所有被引用的局部变量,格式下面说明
};
struct _block_byref_mydata
{
    uint_8* a;  // 总是0
    _block_byref_mydata* b;  // 总是指向该结构体,用途不明
    unsigned long c;
    unsigned long d;    //猜测是__block mask
    __block_byref_id_object_copy e; //用来拷贝__block变量的函数
    __block_byref_id_object_release f;  // 释放__block变量的函数
    NSObject* g;    //指向原__block变量的地址
};


Block类型
  Block的初始类型可能是NSGlobalBlock,也可能是NSStackBlock

  当block内部没有引用到包含Block的最小范围的栈变量时候,则是NSGlobalBlock,否则为NSStackBlock

  调用Block_copy可以从NSStackBlock生成NSMallocBlock,对NSGlobalBlock调用Block_copy返回NSGlobalBlock本身。


变量的存储
  局部变量类型可能有,Objective-C类型,简单类型如int, int*, 结构体,C++类,以及上面各个类型经过__block修饰的变量类型。
  1. Objective-C类型:存储Objective-C指针本身
  2. a.简单类型:存储变量的值,例如int i = 9;存储的是0x00000009,占用4字节,

    b.结构体类型:存储结构体的内容,,例如结构体struct{short i=20, short j=100},存储的是0x00640014,占用空间为8

    c.C++类:存储经过拷贝构造函数生成的新对象内存,如果存在虚表,也写入内存,占用空间和sizeof(class)一致的.

  3.__block修饰的变量:指向_block_byref_mydata结构体的指针,当变量经过__block修饰之后,会生成_block_byref_mydata结构体,同时把指针放入block变量中,占用4字节


如何对变量进行retain操作

  因为descriptor.copy_helper函数是编译器根据当前有多少个引用了的变量和变量存储未知动态生成的,所以可以很好的规定哪些地址是需要retain的,哪些是简单类型只需要拷贝内容的,哪些是__block修辞的变量需要特殊操作的。


参考:http://www.cocoawithlove.com/2009/10/how-blocks-are-implemented-and.html

#include <stddef.h> #include <stdint.h> #include <stdio.h> #include <string.h> #include <assert.h> void bulk_mem_copy(void *dst, const void *src, size_t size) { if(!dst || !src || 0 == size) { return; } uint8_t *d = dst; const uint8_t *s = src; if (d > s && d < s + size) /* 如果有重叠区域则从后往前拷贝 */ { d += size; s += size; while (size--) { *--d = *--s; } } else /* 正向拷贝 */ { size_t chunk = size / sizeof(uint64_t);/* 计算64块数量 */ uint64_t *d64 = (uint64_t*)d;/* 将目标指针转换为64指针:允许按机器字长操作 */ const uint64_t *s64 = (const uint64_t*)s; /* 将源指针转换为64指针:确保对齐访问 */ while (chunk--) /* 循环拷贝完整64块 */ { *d64++ = *s64++; } d = (uint8_t*)d64; s = (const uint8_t*)s64; size %= sizeof(uint64_t);/* 计算剩余字节 */ while (size--) { *d++ = *s++; } } } int mem_compare(const void *a, const void *b, size_t size) { const uint8_t *pa = a; const uint8_t *pb = b; for (size_t i = 0; i < size; i++) { if (pa[i] != pb[i]) { printf("差异置: %zu, 预期: 0x%02X, 实际: 0x%02X\n", i, pb[i], pa[i]); return -1; } } return 0; } void test_overlap_copy() /* 重叠区域 */ { printf("\n===== 测试重叠区域拷贝 =====\n"); char buffer[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"; const char *src = buffer; char *dst = buffer + 5; printf("原始: %s\n", buffer); bulk_mem_copy(dst, src, 15); const char *expected = "ABCDEABCDEFGHIJKLPQRSTUVWXYZ"; printf("结果: %s\n", buffer); printf("预期: %s\n", expected); assert(mem_compare(buffer, expected, sizeof(buffer)) == 0); printf("测试通过: 重叠区域拷贝\n"); } void test_large_block_copy() /* 大内存块性能 */ { printf("\n===== 测试大内存块拷贝 =====\n"); const size_t SIZE = 1 << 20; // 1MB uint8_t *src = malloc(SIZE); uint8_t *dst = malloc(SIZE); // 填充随机数据 for (size_t i = 0; i < SIZE; i++) { src[i] = rand() & 0xFF; } bulk_mem_copy(dst, src, SIZE); assert(mem_compare(dst, src, SIZE) == 0); printf("测试通过: 1MB内存块拷贝\n"); free(src); free(dst); } int main() { test_overlap_copy(); test_large_block_copy(); printf("\n所有测试用例通过!\n"); return 0; }十二行和83行报错
最新发布
08-02
我利用这个方法检测应用存在花屏问题,误判率居高不下,请问如何修改降低误判率 def check_screen(self): # 获取屏幕截图并保存为临时文件 screenshot = self.driver.get_screenshot_as_png() screenshot_path = "temp_screenshot.png" with open(screenshot_path, 'wb') as f: f.write(screenshot) # ------------------------ 新花屏检测逻辑(优化版) ------------------------ img_cv = cv2.imread(screenshot_path) height, width, _ = img_cv.shape total_pixels = height * width # 动态调整区域划分(根据屏幕宽高比优化) aspect_ratio = width / height if 1.5 <= aspect_ratio <= 2.0: # 常见手机竖屏比例 num_rows, num_cols = 4, 8 # 更密集的纵向划分 elif aspect_ratio > 2.0: # 超宽屏 num_rows, num_cols = 3, 12 else: # 其他比例(如平板横屏) num_rows, num_cols = 3, 6 block_h, block_w = height // num_rows, width // num_cols block_list = [] # 特征参数(通过历史数据校准的阈值) FEATURE_THRESHOLDS = { 'variance': 150, # 灰度方差阈值(过低=均匀异常) 'entropy': 2.2, # 灰度熵阈值(过低=颜色集中) 'edge_density': 0.08, # 边缘密度阈值(过高=条纹/噪点) 'contrast': 40 # 对比度阈值(过低=模糊异常) } for row in range(num_rows): for col in range(num_cols): # 计算区域坐标(防止越界) y_start = max(0, row * block_h) y_end = min(height, (row + 1) * block_h) x_start = max(0, col * block_w) x_end = min(width, (col + 1) * block_w) block = img_cv[y_start:y_end, x_start:x_end] gray = cv2.cvtColor(block, cv2.COLOR_BGR2GRAY) h, w = gray.shape block_area = h * w # 特征1:灰度方差(衡量亮度变化) variance = np.var(gray) # 特征2:灰度熵(衡量颜色分布混乱度) hist = cv2.calcHist([gray], [0], None, [256], [0, 256]).flatten() prob = hist / (block_area + 1e-7) # 防止除零 entropy = -np.sum(prob * np.log(prob + 1e-7)) # 平滑处理 # 特征3:边缘密度(Canny边缘检测) edges = cv2.Canny(gray, 50, 150) # 固定阈值(可根据实际调整) edge_pixels = np.count_nonzero(edges) edge_density = edge_pixels / block_area # 特征4:对比度(最大灰度差) contrast = np.max(gray) - np.min(gray) # 记录所有特征值 block_features = { 'variance': variance, 'entropy': entropy, 'edge_density': edge_density, 'contrast': contrast, 'area': block_area, 'coords': (x_start, y_start, x_end, y_end) } block_list.append(block_features) # 计算全局特征基准(用于动态阈值) all_variances = [b['variance'] for b in block_list] all_entropies = [b['entropy'] for b in block_list] global_variance_mean = statistics.mean(all_variances) global_entropy_mean = statistics.mean(all_entropies) # 动态调整阈值(基于全局均值±2倍标准差) dynamic_thresholds = { 'variance': global_variance_mean - 1.5 * np.std(all_variances), # 偏离均值1.5σ视为异常 'entropy': global_entropy_mean - 1.5 * np.std(all_entropies) } # 筛选疑似花屏区域(满足任意2个以上特征异常) flower_blocks = [] for block in block_list: var_anomaly = block['variance'] < dynamic_thresholds['variance'] entropy_anomaly = block['entropy'] < dynamic_thresholds['entropy'] edge_anomaly = block['edge_density'] > FEATURE_THRESHOLDS['edge_density'] contrast_anomaly = block['contrast'] < FEATURE_THRESHOLDS['contrast'] # 至少满足2个异常特征才标记 if sum([var_anomaly, entropy_anomaly, edge_anomaly, contrast_anomaly]) >= 2: # 排除过小区域(面积小于总屏幕的0.5%) if block['area'] >= (total_pixels * 0.005): flower_blocks.append(block) # 计算花屏区域总面积占比(超过5%判定为花屏) flower_area = sum(b['area'] for b in flower_blocks) is_flower_screen = (flower_area / total_pixels) > 0.1 # 使用 PIL 处理图像,检测黑屏和白屏 img_pil = Image.open(screenshot_path).convert('RGBA') color, total = (0, 0, 0), 0 for count, (r, g, b, a) in img_pil.getcolors(img_pil.size[0] * img_pil.size[1]): if a != 0: # 只处理透明度不为 0(即可见)的像素点 color = (color[0] + r * count, color[1] + g * count, color[2] + b * count) total += count if total > 0: dominant_color = (int(color[0] / total), int(color[1] / total), int(color[2] / total)) mean = statistics.mean(list(dominant_color)) is_black_screen = mean < 10 # 判断黑屏 is_white_screen = mean > 254 # 判断白屏 else: is_black_screen = True is_white_screen = False # 保存问题截图(任意异常触发保存) if is_flower_screen or is_black_screen or is_white_screen: save_dir = os.path.join('D:', 'screenshot') os.makedirs(save_dir, exist_ok=True) shutil.copy(screenshot_path, os.path.join(save_dir, 'problem_screenshot.png')) # 删除临时截图文件 os.remove(screenshot_path) return is_flower_screen, is_black_screen, is_white_screen
06-17
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值