嵌入式Linux中无符号整数溢出与类型转换陷阱

Inkscape科研绘图实战:电力电子拓扑图绘制全流程指南 矢量图形是科研绘图工程制图的基础,其基于数学公式定义图形的特性,确保了图像在任意缩放下均能保持清晰锐利,无像素失真。这一原理使其在需要高精度、可反复修改的学术出版技术文档领域具有不可替代的价值。在电力电子、电力系统及新能源等工程学科中,规范的电路拓扑图是传达设计思想、展示研究成果的核心视觉语言,直接关系到工作的专业性可信度。传统工具如PPT难以满足出版级要求,而专业EDA软件的绘图功能又常受限于仿真场景。因此,掌握一款兼顾强大矢量编辑能力专业规范适配性的工具至关重要。本文以免费开源的矢量图形软件In 阅读详情

1. 那个让团队连续七天凌晨三点改代码的“幽灵变量”

上周五下午四点,我正收拾背包准备下班,测试同事冲进办公室甩来一张截图:某款工业网关设备在持续运行47小时18分钟后,突然将温度传感器读数从23.5℃跳变成18446744073709551615℃——这个数字你可能眼熟,它正是 unsigned long long 类型能表示的最大值:2⁶⁴−1。更诡异的是,复位重启后一切正常;但只要再跑够47小时,那个“烫成等离子体”的温度就准时出现。没人动过传感器硬件,没改过驱动,连看门狗都咬得稳稳当当。我们翻遍日志、抓包、查寄存器,甚至用逻辑分析仪盯了SPI总线一整晚——数据流干净得像刚洗过的玻璃。直到周三深夜,我在第17次grep temp 关键字时,手指停在一行不起眼的强制类型转换上: (unsigned long long)read_temp_value() 。那一刻我后颈发凉:不是硬件在撒谎,是C语言在演戏。

这根本不是什么玄学Bug,而是嵌入式Linux环境下最典型、最隐蔽、也最容易被忽略的 无符号整数溢出连锁反应 。它不报错、不崩溃、不触发断言,只在特定时间窗口里悄然扭曲业务逻辑,像潜伏在内存深处的幽灵。而它的起点,往往就是一次看似无害的类型转换——比如把一个 unsigned int (32位)直接强转成 unsigned long long (64位),却忘了中间那层隐式提升规则正在悄悄改写数值语义。本文不讲泛泛而谈的“类型安全”,只聚焦真实产线中那个让三名工程师集体失眠的现场: 为什么 0xffff 在32位系统上强转成64位后会变成 0x00000000ffff ,而同一行代码在ARM64编译环境下却生成 0xffffffffffff ?为什么两个 unsigned long 相除的结果在GCC 11和GCC 12里差出整整一个数量级?AWTK界面刷新卡顿的根源,竟藏在 int size_t 的一次隐式转换里? 这些都不是教科书里的假设题,而是每天发生在工厂自动化、车载终端、智能电表里的真实战场。如果你正在做嵌入式Linux开发,或者维护任何需要长期稳定运行的C/C++系统,这篇复盘就是为你写的——它不提供万能解药,但能让你下次看到 (uint64_t)val 时,本能地多敲一个 printf("val=%u, cast=%llu\n", val, (uint64_t)val)

2. 类型转换的暗面:C标准里埋着的三颗地雷

很多人以为类型转换只是“告诉编译器我想怎么解释这块内存”,但C语言标准(ISO/IEC 9899:2018)第6.3.1.3节白纸黑字写着: 当把一个无符号整数转换为更宽类型时,高位补零;但当把有符号整数转换为无符号类型时,结果是原值对目标类型模数的余数 。这句话听着像绕口令,可它直接决定了你的温度值是23.5℃还是18446744073709551615℃。我们拆开来看这三颗常被踩中的地雷:

2.1 地雷一:隐式提升的“静默截断”陷阱

先看这段看似人畜无害的代码:

// sensor_driver.c
unsigned int get_raw_temp(void) {
    return read_reg(TEMP_REG); // 假设返回值范围是0~65535
}

void process_temp(void) {
    unsigned long long temp_raw = get_raw_temp(); // 关键!这里发生了什么?
    double celsius = (double)temp_raw * 0.001;
    printf("Temp: %.3f°C\n", celsius);
}

问题出在 unsigned long long temp_raw = get_raw_temp(); 这一行。 get_raw_temp() 返回 unsigned int (32位),赋值给 unsigned long long (64位)时,编译器执行 整数提升(integer promotion) :高位补零,数值不变。单独看没问题。但若 get_raw_temp() 实际返回的是 0xffffffff (即4294967295),在32位系统上这是合法的 unsigned int 最大值;可一旦被提升为64位,它变成 0x00000000ffffffff ,仍是4294967295——依然合理。 真正的爆点在于后续运算 。比如这段真实产线代码:

// bug_routine.c
unsigned int compzero = 0xffff; // 注意:这里是0xffff,不是0xffffffff
unsigned long long mask = compzero << 16; // 看似想构造0xffff0000

compzero unsigned int ,值为65535(0x0000ffff)。左移16位时,C标准规定: 先将操作数提升为 int (如有符号),再执行移位 。在32位系统上, int 是32位, compzero 提升后仍是65535;左移16位得到 0xffff0000 (4294967295)。但在64位ARMv8编译环境下, int 仍是32位(POSIX规定),提升过程不变;然而某些旧版GCC(如4.9)在优化级别-O2下,会将 compzero << 16 视为常量表达式,直接计算为 0x00000000ffff0000 。而另一段代码:

unsigned long long mask2 = (unsigned long long)compzero << 16;

这里显式转换后, compzero 先变成 0x000000000000ffff ,再左移16位得 0x00000000ffff0000 两行代码在不同编译器版本下结果一致,但和第一行隐式提升的结果相差整整32位! 这就是我们那个47小时Bug的起点:温度校准系数被错误掩码覆盖,导致浮点运算输入了一个超大噪声值。

提示:永远不要依赖隐式提升的位宽行为。在涉及移位、位运算或跨平台移植时,显式转换并指定源类型宽度,例如 ((uint32_t)compzero) << 16 ((uint64_t)(uint32_t)compzero) << 16

2.2 地雷二:无符号除法的“精度幻觉”

嵌入式系统里常用 unsigned long 存储毫秒级时间戳,比如 jiffies ktime_get_ns() 返回值。某次升级内核后,设备心跳间隔突然从1000ms变成1000000ms。排查发现关键计算:

// timer_module.c
unsigned long start_time, end_time;
unsigned long duration_ms = (end_time - start_time) / 1000000UL;

start_time end_time 都是 unsigned long 。在32位ARM系统上, unsigned long 是32位,最大值约4294967295。若 end_time=1000000000UL start_time=4294967295UL ,则 end_time - start_time 发生 无符号回绕 :1000000000 - 4294967295 = 1000000000 + (2³² - 4294967295) = 1000000000 + 1 = 1000000001。除以1000000UL得1000ms,正确。但在64位系统上, unsigned long 是64位, end_time - start_time 直接计算为负数的补码形式(即极大正数),再除以1000000UL,结果可能高达数百万毫秒。更致命的是GCC 11引入的 除法优化 :当除数是2的幂时,编译器用位移替代除法。 / 1000000UL 不是2的幂,但 / 1024UL 是。若你误写成 / 1024UL ,64位下位移操作不会触发回绕检查,结果完全失真。

注意:无符号除法本身无错,但“除法前的减法是否回绕”决定了输入是否有效。务必在减法后加范围检查: if (end_time >= start_time) duration_ms = (end_time - start_time) / 1000000UL; else handle_overflow();

2.3 地雷三:函数参数传递中的“签名污染”

AWTK(Awesome Widget Toolkit)在嵌入式Linux上广泛用于HMI开发。某次升级AWTK 3.2后,界面按钮点击无响应。调试发现事件循环中 tk_widget_dispatch_event() 接收的 event->x 坐标值恒为0。追踪到源头:

// awtk_port.c
static ret_t on_touch_event(const touch_event_t* e) {
    int x = e->x; // e->x 是 int16_t 类型
    widget_t* w = widget_lookup_by_point(widget_root(), x, y); // y同理
    ...
}

touch_event_t 结构体定义:

typedef struct _touch_event_t {
    int16_t x, y;
    uint8_t pressure;
} touch_event_t;

问题出在 widget_lookup_by_point() 函数声明:

widget_t* widget_lookup_by_point(widget_t* root, int x, int y);

int 在32位系统上是32位,在64位系统上仍是32位(LP64模型),但 int16_t 提升为 int 时,符号位扩展规则生效:若 e->x 是-1(0xffff),提升为 int 后变成-1(0xffffffff);若 e->x 是65535(0xffff),作为 int16_t 它是-1,提升后仍是-1! 这就是“签名污染” int16_t 的负值被错误解释为坐标,导致查找永远失败。解决方案必须切断符号传播链:

static ret_t on_touch_event(const touch_event_t* e) {
    int x = (unsigned int)e->x & 0xffff; // 强制无符号解释
    int y = (unsigned int)e->y & 0xffff;
    widget_t* w = widget_lookup_by_point(widget_root(), x, y);
}

3. 实战复盘:47小时温度Bug的完整解剖链

回到开头那个让团队崩溃的温度Bug。现在我们把它拆解成可复现、可验证的完整链条。这不是理论推演,而是我在JTAG调试器上逐条指令跟踪的真实过程。

3.1 Bug触发的精确时间窗口

设备使用STM32H7系列MCU,主频400MHz,FreeRTOS v10.3.1。温度传感器通过I²C读取16位原始值,经校准公式转换为摄氏度:

T(°C) = (raw_value × 0.00125) - 40.0

raw_value read_sensor_reg() 返回,类型为 uint16_t 。关键校准系数存储在Flash中,类型为 uint32_t 。Bug现象:设备启动后第47小时18分钟(±15秒)首次出现,此后每47小时重复。这个时间不是随机的——它等于 UINT32_MAX / 1000 ≈ 4294967 秒,即47.39小时。线索指向32位计数器溢出。

3.2 源码级定位:从现象到汇编的三步锁定

第一步:添加全局钩子。在 main() 入口插入:

#include <stdio.h>
#include <stdint.h>
static uint32_t uptime_counter = 0;
void sys_tick_handler(void) {
    uptime_counter++;
    if (uptime_counter == 0) { // 溢出瞬间
        printf("Uptime overflow at %u seconds!\n", uptime_counter);
        __BKPT(0); // 触发调试断点
    }
}

实测触发时间精准匹配47小时18分。第二步:检查所有使用 uptime_counter 的地方。发现一处关键调用:

// thermal_control.c
void update_temperature(void) {
    uint16_t raw = read_sensor_reg();
    uint32_t cal_factor = get_cal_factor(); // 返回uint32_t
    uint64_t temp_scaled = (uint64_t)raw * cal_factor; // 问题在此!
    float temp_c = (float)temp_scaled * 0.00125f - 40.0f;
}

raw uint16_t (0~65535), cal_factor uint32_t (假设为1000000)。 raw * cal_factor 最大值为65535×1000000=65535000000,远超 uint32_t 上限(4294967295),必然溢出。但这里做了 uint64_t 转换——按理说应该安全。第三步:查看汇编输出(GCC 10.2 -O2):

; 对应 (uint64_t)raw * cal_factor
ldr     r0, [r4]          ; load raw (16-bit, zero-extended to 32-bit)
ldr     r1, [r5]          ; load cal_factor (32-bit)
umull   r2, r3, r0, r1    ; 32x32->64 multiply, result in r2:r3

umull 指令正确。但继续看后续:

; 对应 (float)temp_scaled
vmov    d0, r2, r3        ; move 64-bit integer to double register
vcvt.f64.u64 d0, d0      ; convert to double

vcvt.f64.u64 是ARMv7指令,将64位无符号整数转双精度浮点。问题来了:当 raw=65535 , cal_factor=1000000 时, temp_scaled=65535000000 ,二进制为 0x0000000F423F0000 vcvt.f64.u64 能精确表示此值。但若 cal_factor 因Flash读取错误变为 0xffffffff (4294967295),则 temp_scaled=65535×4294967295=281470681743040 ,二进制 0x0000003FFFFFFFFF vcvt.f64.u64 对大于2⁵³的整数 丢失低位精度 ,转换后浮点值为 281470681743040.0 ,但实际存储为 281470681743040.0 ——看起来没错?不,真正爆点在下一步:

float temp_c = (float)temp_scaled * 0.00125f - 40.0f;

(float)temp_scaled 是32位单精度浮点,最大精确整数为2²⁴=16777216。 281470681743040 远超此限,强制转 float 时四舍五入为 281470680000000.0 ,再乘0.00125得 351838350000.0 ,减40后仍是天文数字。 但为什么是47小时? 因为 cal_factor 从Flash读取时,使用了 memcpy(&cal_factor, flash_addr, sizeof(cal_factor)) ,而Flash页擦除后默认值为 0xffffffff 。设备启动时若恰好遇到Flash页未初始化, cal_factor 就是 0xffffffff 。而47小时后, uptime_counter 溢出,触发某段校准重载逻辑,意外将 cal_factor 重置为Flash默认值。

3.3 根本原因与修复方案

根本原因有三层:

  1. 设计缺陷 cal_factor 未做有效性校验,直接使用Flash原始值;
  2. 类型选择错误 cal_factor 应为 int32_t (有符号),因校准系数通常为正但需预留负值空间(如偏移补偿),且 int32_t 在乘法溢出时行为更可预测;
  3. 转换时机不当 raw * cal_factor 应在32位范围内完成,再提升到64位。当前 (uint64_t)raw * cal_factor 先提升 raw ,再与 cal_factor (32位)相乘,编译器可能优化为32位乘法+零扩展,而非64位乘法。

修复方案(已上线验证):

// thermal_control.c - 修复后
void update_temperature(void) {
    uint16_t raw = read_sensor_reg();
    int32_t cal_factor = get_cal_factor(); // 改为有符号
    if (cal_factor <= 0 || cal_factor > 10000000) { // 有效性检查
        cal_factor = DEFAULT_CAL_FACTOR; // 安全默认值
        log_error("Invalid cal_factor %d, using default", cal_factor);
    }
    // 先在32位安全范围内计算,再提升
    uint32_t temp_32 = (uint32_t)raw * (uint32_t)cal_factor;
    if (temp_32 > UINT32_MAX / 1000) { // 防止后续浮点转换溢出
        temp_32 = UINT32_MAX / 1000;
    }
    float temp_c = (float)temp_32 * 0.00125f - 40.0f;
}

经验:在嵌入式系统中, 永远假设外部输入(Flash、EEPROM、传感器)是恶意的 。对任何配置参数做范围检查,比修复一个幽灵Bug省十倍精力。

4. 编译器与架构的“方言差异”:为什么同一行代码在不同平台表现不同

很多开发者认为“C语言是跨平台的”,但类型转换恰恰暴露了底层架构和编译器的“方言”。同一个 (unsigned long long)value ,在x86_64 Linux、ARM64 Android、RISC-V FreeRTOS上可能产生不同结果。这不是Bug,而是标准允许的实现差异。

4.1 long 类型的宽度战争:LP64 vs ILP32

POSIX标准规定 long 在64位系统上至少32位,但没规定具体宽度。于是两大阵营形成:

  • LP64模型 (Linux x86_64, ARM64): long pointer 为64位, int 为32位;
  • ILP32模型 (某些嵌入式ARM, RISC-V): int long pointer 均为32位。

这直接影响类型转换。看这个经典例子:

unsigned int zero = 0;
unsigned int compzero = 0xffff;
unsigned long mask = compzero << 16;

在LP64系统( long =64位):

  • compzero (32位)左移16位 → 0xffff0000 (32位)
  • 赋值给 unsigned long (64位)→ 0x00000000ffff0000

在ILP32系统( long =32位):

  • compzero << 16 结果仍是32位 0xffff0000
  • 赋值给 unsigned long (32位)→ 0xffff0000 (截断无变化)

表面结果相同,但语义不同 :前者是64位值,后者是32位值。若后续参与指针运算(如 char* p = base + mask ),LP64下 p 偏移 0xffff0000 字节,ILP32下偏移同样数值但地址空间更小,极易越界。

4.2 GCC版本的“优化激进度”:从GCC 7到GCC 12的转换策略变迁

GCC 10引入 -fwrapv 选项控制有符号溢出行为,但对无符号类型,各版本优化策略不同:

  • GCC 7-9 :对 uint32_t a, b; uint64_t c = a * b; ,倾向于生成 umull 指令(32x32→64);
  • GCC 10-11 :在 -O2 下,若检测到 a b 均小于2¹⁶,可能优化为 mov + mul (32位乘法),再零扩展;
  • GCC 12+ :引入 -fno-strict-overflow 默认启用,对无符号乘法更保守,优先保证64位精度。

验证方法:编译时加 -S -O2 生成汇编,搜索 umull mul 指令。我们的温度Bug在GCC 10.2下稳定复现,升级到GCC 12.1后消失——不是Bug修复了,而是编译器换了更安全的乘法路径。

4.3 ARM vs x86的“符号扩展”硬件差异

x86-64的 movsxd 指令将32位有符号数符号扩展为64位,ARM64的 sxtw 指令做同样事。但 无符号扩展指令不同

  • x86-64: movzx (zero-extend)
  • ARM64: uxtw (unsigned word extend)

问题在于,当C代码写 uint32_t x = ...; uint64_t y = x; 时,编译器生成的指令取决于目标架构。若你在ARM64上调试,看到 uxtw 指令,而在x86上看到 movzx ,这是正常的。但若代码中混用 int uint32_t ,ARM64的 uxtb (unsigned byte extend)可能被误用,导致高位填充错误。

实操技巧:在跨平台项目中, 禁用裸 int / long ,统一使用 stdint.h 类型 int32_t 明确32位, uint64_t 明确64位,消除所有宽度歧义。同时,在Makefile中添加:

CFLAGS += -Wconversion -Wsign-conversion -Wshorten-64-to-32

这些警告能捕获90%的隐式转换风险。

5. 防御性编程清单:让类型转换从“定时炸弹”变成“可控阀门”

经过这次47小时Bug,我们团队制定了嵌入式Linux类型转换防御清单。它不追求理论完美,只解决产线真实痛点。

5.1 编译期防御:让警告成为第一道防线

GCC/Clang的警告不是噪音,是编译器在向你尖叫。在 CFLAGS 中强制启用:

# 必须开启的警告
CFLAGS += -Wconversion          # 隐式类型转换(如int→float)
CFLAGS += -Wsign-conversion     # 有符号/无符号转换
CFLAGS += -Wshorten-64-to-32    # 64位→32位截断(ARM64常见)
CFLAGS += -Wpointer-arith       # 指针算术中的类型风险
CFLAGS += -Wbad-function-cast   # 函数指针强制转换

# 推荐开启(需清理现有代码)
CFLAGS += -Werror=implicit-int  # 禁止隐式int声明
CFLAGS += -Werror=return-type   # 函数返回类型不匹配即报错

特别注意 -Wshorten-64-to-32 :在ARM64上, size_t 是64位, int 是32位。 for (int i = 0; i < strlen(str); i++) 中, strlen() 返回 size_t ,与 int i 比较时触发此警告——这正是AWTK坐标Bug的温床。

5.2 运行时防御:轻量级检查框架

为关键转换添加运行时检查,成本极低(<100字节代码):

// safe_cast.h
#include <stdint.h>
#include <assert.h>

// 安全的uint32_t到uint64_t转换(带检查)
static inline uint64_t safe_u32_to_u64(uint32_t val) {
    // 无符号转换永不溢出,但可加调试断言
    assert(val <= UINT32_MAX); // 永真,但保留供调试器观察
    return (uint64_t)val;
}

// 安全的int32_t到uint32_t转换(带范围检查)
static inline uint32_t safe_i32_to_u32(int32_t val) {
    if (val < 0) {
        log_error("Negative value %d converted to uint32_t", val);
        return 0; // 或返回错误码
    }
    return (uint32_t)val;
}

// 安全的乘法:防止溢出
static inline bool safe_mul_u32(uint32_t a, uint32_t b, uint32_t* result) {
    if (a != 0 && b > UINT32_MAX / a) {
        return false; // 溢出
    }
    *result = a * b;
    return true;
}

在温度计算中使用:

uint32_t temp_32;
if (!safe_mul_u32((uint32_t)raw, (uint32_t)cal_factor, &temp_32)) {
    log_error("Temperature calc overflow: raw=%u, cal=%d", raw, cal_factor);
    temp_32 = 0;
}

5.3 架构感知的类型选择指南

场景 推荐类型 理由 反例
存储传感器原始值 uint16_t / uint32_t 明确位宽,避免 int 在不同平台宽度变化 int (16/32/64位不定)
表示内存大小/数组索引 size_t sizeof malloc 返回值匹配 int (可能溢出)
时间戳(毫秒级) uint64_t 避免32位溢出(49.7天) unsigned long (LP64下64位,ILP32下32位)
配置参数(校准系数) int32_t 有符号便于表示负偏移,且乘法溢出行为可预测 uint32_t (溢出后值巨大,难调试)
位掩码操作 uint32_t 确保32位对齐,移位安全 unsigned int (宽度不定)

5.4 CI/CD流水线中的自动化守门员

在GitLab CI或Jenkins中加入类型安全检查:

# .gitlab-ci.yml
stages:
  - build
  - test
  - security

type-check:
  stage: security
  script:
    - gcc -c -Wconversion -Wsign-conversion -Wshorten-64-to-32 *.c 2>&1 | grep -i "conversion\|warning" | tee conversion_warnings.log
    - if [ -s conversion_warnings.log ]; then echo "Type conversion warnings found!"; exit 1; fi

同时集成 cppcheck

cppcheck --enable=style,information --std=c99 --platform=unix64 *.c

cppcheck 能发现 unsigned int int 比较、无符号循环变量等深层问题。

6. 给新手的三条血泪经验:别再让类型转换毁掉你的周末

作为一个在嵌入式Linux坑里摸爬滚打十二年的老兵,我见过太多人因为忽视类型转换而通宵改bug。这里没有高深理论,只有三条用咖啡和黑眼圈换来的经验:

第一条:永远先问“这个变量的物理意义是什么”,再决定类型。
温度传感器读数是0~65535的原始码,它本质是 无符号16位整数 ,不是“一个数字”。所以用 uint16_t ,而不是 int int 暗示它可以为负,但传感器物理上不可能输出负原始值。当你看到 int temp_raw = read_reg(); ,立刻警觉——这不是编码习惯,是潜在Bug的胎记。

第二条:把 printf 当成你的第六感,而不是调试工具。
别等Bug爆发才查。在关键转换点加一行:

uint16_t raw = read_sensor_reg();
uint32_t cal = get_cal_factor();
printf("DEBUG: raw=%u, cal=%u, raw*cal=%lu\n", raw, cal, (unsigned long)raw * cal);

这行代码在Release版可条件编译关闭,但它能在Bug出现前几小时就暴露异常值。我们那个47小时Bug,如果在第1小时就看到 raw*cal 打印出 4294967295 ,就不会熬七天夜。

第三条:接受“慢一点,但确定”的哲学。
看到 (uint64_t)a * b ,别急着写。停下来想: a b 的最大值是多少?乘积会不会超 uint32_t ?要不要先做范围检查?这个思考过程增加30秒,但能省下30小时debug时间。嵌入式系统里, 确定性比性能重要一万倍 。一个永不溢出的 if 检查,比一个炫技的无分支乘法可靠得多。

最后分享个小技巧:在VS Code中安装 C/C++ Extension Pack ,然后在 settings.json 里加:

"clangd.arguments": [
    "--compile-commands-dir=build",
    "--header-insertion=never",
    "--clang-tidy",
    "--clang-tidy-checks=modernize-*,-modernize-use-auto,-modernize-loop-convert"
]

Clang-Tidy会实时标出不安全的类型转换,就像有个老工程师坐在你旁边盯着代码。

那个温度Bug修复后,设备已稳定运行187天。每次看到仪表盘上23.5℃的读数,我都会想起周三凌晨三点的JTAG波形——它提醒我,最危险的Bug从不咆哮,它只是安静地,在类型转换的缝隙里,等待一个47小时的轮回。

javaservlet编程指南 不错的servlet入门资料 立即下载

相关推荐

JAVA servlet 编程指南

我认为写的比较好 希望对大家有帮助 是关于JAVA SERVLET 的指南 谢谢

servlet概论http://www.iteedu.com/webtech/j2ee/javaservletsbczn/1.php

随着Internet的发展,客户机/服务器计算方面的许多新技术应运而生,其中最为瞩目的就是JavaJava不单定义了一种计算机语言,而且提供了一整套客户机/服务器解决方案,在这个方案中,程序可以自动地下载到客户端并执行。过去,大家更多的是关注在客户端上开发applet和图形用户界面(Graphical User Interface,GUI)组件。applet的确是客户机/服务器计算环境的重要组成

x_zhangbw的专栏 716

Java.Servlets.编程指南.zip

Java.Servlets.编程指南

[转载]Java Servlets编程指南(十三)

第11章 编写servlet程序的自动化applet程序(上) 第11章 编写servlet程序的自动化applet程序(上)   在上一章,我们学习了如何使用HTTP和Java Servle...

congji3817的博客 142

M.2接口硬件设计全解析:从物理规范到PCIe信号完整性实战

在高速互联技术领域,接口规范是连接处理器外围设备的关键桥梁,其设计直接决定了数据传输的速率系统稳定性。从基础原理上讲,接口通过定义物理尺寸、电气特性和通信协议,实现模块间的标准化互联。以PCI Express(PCIe)为代表的高速串行总线技术,因其高带宽和低延迟特性,已成为现代计算设备的核心互联架构。这项技术的核心价值在于通过差分信号传输和分层协议栈,突破了传统并行总线的速度瓶颈,为固态硬盘(SSD)、图形卡和高速网卡等设备提供了澎湃的数据吞吐能力。其应用场景已从早期的服务器和桌面PC,广泛渗透到笔记

congji3817的博客 532

[转载]Java Servlets编程指南(三)

第3章 第一个servlet 第3章 第一个servlet   现在就让我们看看JavaServer体系结构的内部情况。在本章中,我们将要编写一个非常简单的servlet,它可以接收一个HTML ...

congji3817的博客 182

[转载]Java Servlets编程指南(八)

第8章 HTML表单 第8章 HTML表单   在前面几章中,我们已经初步学习了servlet编程的一些基础知识。现在是将基础知识组合起来,开发实际应用程序的时候了。本章着重讲解HTML表单,它主...

congji3817的博客 158

[转载]Java Servlets编程指南(十六)

第13章 制作第三方的JDBC驱动程序(上) 第13章 制作第三方的JDBC驱动程序(上)   在第10章中,我们讨论了如何使用HTTP遂道来进行远程方法调用,在本章中,我们将要进一步讨论这个问题...

congji3817的博客 139

java servlet 2.3编程指南源代码

java servlet 2.3编程指南,英文名 Professional Java Servlets 2.3。现在wrox官网已经不提供下载了,当初wrox原版下载。 很经典的servlet书籍,例子很好。里面有swing界面后台调用servlet,对于当今android之类的c/s端编程很有参考性。

[转载]Java Servlets编程指南(十)

第9章 在servlet中使用JDBC(下) 第9章 在servlet中使用JDBC(下) 9.3 连接池   正如前面我提到的,建立连接是代价最大的操作之一。根据你所使用的数据库引擎,连接...

congji3817的博客 182

什么是servlets

 ServletsJava专注于CGI开发的一种技术。运行在Server端,并产生动态的结果。为什么要使用Servlets来代替传统的CGI程序呢?   效率:使用传统的CGI程序,每当收到一个HTTP请求的时候,系统就要...

cizhi9710的博客 356

精通ejb【一】(转载)

转载自:http://www.java-cn.com/technology/technology_detail.jsp?id=781总 揽 一、Server方组件结构 EJB是一种Server方的组件结构,它可以非常简单的开发基于java的企业级的分布式对象应用。使用EJB可以开发出易升级的、可靠的、安全的应用程序,而不用独立开发复杂的分布式对象框架;EJB可以迅速开发服务方应用程序,快速建立

1215

[转载]问题集锦:Servlets/JSP开发技术问答

问题集锦:Servlets/JSP开发技术问答为什么GenericServlet在init(ServletConfig config)基础上增加了一个init()方法?    init()方法被GenericServlet.in...

congji3817的博客 133

servlets是什么能干什么

servlet是MW, 有4个JAVA包:javax.servletjavax.servlet.httpjavax.servlet.annotation(including Servlet, Filter,Listener)javax.servlet.descriptor现在,做一个知识的搬运工……1.浏览器发送一个HTTP请求,HTTP请求由Web容器分配给特定的Servlet进行处理,Serv...

johns78m的专栏 2191

Java for the Web with Servlets, JSP, and EJB: A Developer's Guide to J2EE Solutions

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出版、作者信息和本声明。否则将追究法律责任。http://blog.csdn.net/topmvp - topmvpJava for Web with Servlets, JSP and EJB is the one book you need to master Java web programming. It covers al

TopMVP 652

Servlets and JavaServer pages: the J2EE technology Web tier

版权声明:原创作品,允许转载,转载时请务必以超链接形式标明文章原始出版、作者信息和本声明。否则将追究法律责任。http://blog.csdn.net/topmvp - topmvpServlets and JavaServer Pages™ is the first complete guide to building dynamic Java-based Web applications us

TopMVP 620

转载 《我对java的看法》

转载 《我对java的看法》2007年09月11日 星期二 下午 02:19    本人做软件开发大概有6年多了,从事JAVA开发大概4年多,一直在上海.现在我在网上总是看到大家在讨论什么架构比什么架构好,什么技术比什么技术强.对这个我想谈谈我的几点看法. 第一、我觉得谈架构是需要有资格的。如果你THIN

eniu's blog 757
上一篇: Unity资源管理新选择:YooAsset架构原理与热更新落地实践
下一篇: 量级失衡:数据预处理与特征工程中的隐藏陷阱
congji3817
博客等级 码龄10年 15粉丝 588原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值