/*
 * 04_fd_set_internals.c —— fd_set 内部位图原理探秘
 *
 * 编译: gcc 04_fd_set_internals.c -o fd_internals
 * 运行: ./fd_internals
 *
 * 这个示例不调用 select，只是把 fd_set 的内部布局打印出来，
 * 帮助你直观理解「为什么 fd_set 是位图」、「为什么有 1024 限制」。
 */

#include <stdio.h>
#include <string.h>
#include <sys/select.h>

static void dump_fd_set(const char *tag, fd_set *s) {
    unsigned char *bytes = (unsigned char *)s;
    size_t bits = sizeof(*s) * 8;

    printf("[%s] 总大小 = %zu 字节 = %zu bit (理论最多支持 %zu 个 fd)\n",
           tag, sizeof(*s), bits, bits);

    /* 找出所有为 1 的 bit */
    printf("    bit 为 1 的 fd: ");
    int found = 0;
    for (size_t i = 0; i < bits; i++) {
        size_t byte = i / 8, bit = i % 8;
        if (bytes[byte] & (1u << bit)) {
            printf("%zu ", i);
            found = 1;
        }
    }
    if (!found) printf("(无)");
    printf("\n");

    /* 打印前 16 字节的二进制布局 */
    printf("    前 16 字节十六进制: ");
    for (size_t i = 0; i < 16 && i < sizeof(*s); i++) {
        printf("%02x ", bytes[i]);
    }
    printf("\n\n");
}

int main(void) {
    fd_set s;

    FD_ZERO(&s);
    dump_fd_set("初始 (FD_ZERO 后)", &s);

    FD_SET(0, &s);     /* fd=0 */
    FD_SET(3, &s);     /* fd=3 */
    FD_SET(7, &s);     /* fd=7 */
    FD_SET(63, &s);    /* fd=63 (位于第一个 long 的最高位) */
    FD_SET(64, &s);    /* fd=64 (跨到第二个 long) */
    dump_fd_set("FD_SET(0,3,7,63,64) 后", &s);

    FD_CLR(3, &s);
    dump_fd_set("FD_CLR(3) 后", &s);

    printf("FD_ISSET(7, &s) = %d\n", FD_ISSET(7, &s));
    printf("FD_ISSET(3, &s) = %d (已清除)\n", FD_ISSET(3, &s));

    printf("\n💡 关键启示:\n");
    printf("   1. 每个 fd 只占 1 bit -> 极度省空间\n");
    printf("   2. 位图大小 = FD_SETSIZE = 1024 -> 这是编译期常量\n");
    printf("   3. FD_SET(2000, &s) 会越界写入 -> 未定义行为，可能踩坏内存\n");
    return 0;
}
