嵌入式知識日常問題記錄及用法總結(一)

文章目錄

  • 摘要
  • 問題一、內核啟動流程
    • 1.1 ARM內核
      • 上電復位與BootROM執行?
      • 啟動代碼(Startup Code)執行
      • 跳轉到用戶程序
    • 1.2 內存管理
  • 問題二、C語言基礎
    • 2.1 常量指針和指針常量區別
    • 2.2.函數指針和指針函數區別
    • 2.3 關鍵字Volatile
    • 2.4 隊列結構體數據



摘要

嵌入式C語言中,一些常見的問題總結。

問題一、內核啟動流程

1.1 ARM內核


Reset_Handler   PROCEXPORT  Reset_Handler                     [WEAK]IMPORT  SystemInitIMPORT  __mainLDR     R0, =SystemInitBLX     R0LDR     R0, =__mainBX      R0ENDP

上電復位與BootROM執行?

  • ?復位向量定位?:

    芯片上電后,ARM內核從固定地址(通常為0x00000000)讀取復位向量(Reset Vector)。該地址存放初始棧指針(MSP)?? 和復位處理函數地址(Reset_Handler)??。

  • ?BootROM初始化?:

    內置的BootROM固件執行以下操作:

    • 初始化時鐘、內存控制器、關閉看門狗和中斷。

    • 根據啟動模式(如Flash/SD卡啟動)加載下一階段代碼(如Bootloader或用戶程序)。

啟動代碼(Startup Code)執行

啟動代碼(通常由工具鏈或芯片廠商提供,如IAR或Keil的startup_*.s)依次完成以下任務:

  1. ?堆棧初始化?:

    • 設置主堆棧指針(MSP),指向棧頂地址(如sfe(CSTACK))。
  2. ?硬件初始化?:

    • 調用SystemInit()函數,配置系統時鐘、FPU(若啟用)、電源管理模塊,并關閉看門狗。
  3. ?數據段初始化?:

    • ?.data段(初始值非零的全局變量):從Flash拷貝初始值到RAM。

    • ?.bss段(未初始化或初始值為零的全局變量):將對應RAM區域清零。

  4. ?中斷向量表重定位?:

    • 將中斷向量表從Flash復制到RAM(可選),并更新VTOR(向量表偏移寄存器)。

跳轉到用戶程序

  • ?調用main函數?:

    通過__main__iar_program_start(IAR)等函數完成C運行時環境初始化,最終跳轉至用戶main()函數入口。

  • 硬件層?:BootROM初始化基礎外設,加載啟動代碼。

  • ?固件層?:啟動代碼配置堆棧、時鐘、數據段,建立C運行環境。

  • ?軟件層?:跳轉main()執行用戶邏輯。

1.2 內存管理

對于FLASH來說,存在有

RW-DATA:可讀可寫數據,也就是全局變量,指的是存儲的初始值。例如int x = 10;初始值是:10。
因為全局變量需要整個聲明周期使用,因此在運行的時候,直接將這一部分復制到RAM空間,方便快速調用,相當于是用空間換時間

RO-DATA:表示只讀數據,指的是常量數據。如:const修飾的全局變量,字符串字面量,以及編譯器生成的常量表。通常不需要搬運到RAM,這是因為RO-DATA在運行期間是不會修改的,無需使用RAM的可讀可寫特性,相當于是節約RAM的使用空間,同時Flash掉電不丟失數據,保證常量持久化。

若RO-DATA被高頻訪問?(如實時解碼表),且Flash訪問速度慢(如某些NAND Flash),可將其復制到高速RAM(如片內SRAM)以加速訪問。

ZI-DATA:僅統計未初始化/零初始化的全局和靜態變量,未初始化的全局變量默認狀態是0。

相對應的在啟動的時候,需要將RW-DATA和ZI-DATA復制到RAM空間,RAM空間是用來運行的空間,RAM從上到下是:棧空間、堆空間、.data、.bss段

在這里插入圖片描述

在程序運行的時候,裸機嵌入式系統(如 STM32)??:CPU 直接從 Flash 讀取指令執行(程序編譯后,函數代碼(機器指令)存儲在 .text 段),無需搬運到 RAM(稱為 XIP 技術)。函數調用時,棧幀(Stack Frame)保存 ?返回地址、參數、局部變量,而非函數代碼本身,那而對于函數來說:

函數調用? → ?動態輕量化?:用棧幀實現“按需分配、自動回收”,以極低成本支持嵌套調用、遞歸、中斷等動態場景。

在調用我們寫的程序函數的時候,我們需要處理函數內部的局部變量、還需要知道一件事情那就是我們調用以后還需要返回到調用的地方(返回地址,函數執行完應該跳回的位置)、還有參數傳遞(需傳遞給被調函數的值)以及寄存器保護(防止被調用函數破壞調用者寄存器)。這些內容每一個函數調用都是不一樣的,并且還是循環調用,那么我們就需要設計一個位置最好是能反復應用,相當于是一個車站,可以供天南海北的人去往各地,然后又能回來。那么這個地方就是RAM的棧空間,或者是堆空間。

在棧空間:為當前調用的函數分配一個棧幀,該棧幀是一個連續的內存塊,包含上述所有信息,并且這個是自動管理的,函數進入時棧幀入棧,退出時自動釋放(僅需移動棧指針SP),避免手動內存管理錯誤。遞歸或多層調用時,棧幀按調用順序疊加,后調用的先釋放(LIFO特性)。

棧溢出(遞歸過深)會導致程序崩潰,棧空間耗盡會覆蓋其他內存區域(如全局變量)。此外:棧幀的隔離也會保證程序穩定。

問題二、C語言基礎

2.1 常量指針和指針常量區別

常量指針:char const * p : 構成是 const 是常量,而 * p 是指針,因此是常量指針叫法。

首先 * p 是一個指針,也就是一個地址,直接分析似乎不是那么好分析,姑且先將常量作為重點,也就是最中這個地址存的數據是不能被改變的,所以常量是在前面。

應用在:函數參數傳遞只讀數據(如字符串、配置結構),避免內部誤改。

指針常量 char * const p:指針常量,就理解成指針是一個常量,那么這就簡單了,指針是常量,也就是地址是常量,那么就說明地址是不能改變的,所以是右定向,這樣就只需要刷新地址上面的數據就可以了。

應用在:固定資源訪問(如硬件寄存器地址不可變,但需修改寄存器值)。

2.2.函數指針和指針函數區別

函數指針:就是我們聲明了一個指針,只不過指針類型是函數。

指針函數:本質是函數,返回類型為指針,用于返回地址(如動態內存地址)。

?類型??聲明形式??關鍵語法特征?
函數指針int (*ptr)(int, int)*與指針名用括號綁定:(*ptr)
指針函數int* func(int size)*緊貼返回類型:int*
?維度??函數指針??指針函數?
本質變量(存儲地址)函數(返回地址)
內存位置數據段(全局)或棧(局部)代碼段(函數體)
安全風險錯誤跳轉導致崩潰返回無效指針(懸空指針、內存泄漏)
典型用途回調、插件系統、狀態機內存分配、硬件抽象、數據查詢
  1. 函數指針?:

    • 需確保調用函數與指針簽名一致(參數類型、返回值);

    • 避免懸空指針:若指向的函數被釋放,調用會導致崩潰;

  2. ?指針函數?:

    • ?禁止返回局部變量地址?:函數退出后局部變量失效,返回其地址引發未定義行為;

    • ?動態內存需手動釋放?:返回malloc的指針時,調用者必須free避免內存泄漏。

并且為函數指針成員(如SendBeforSendOverReciveNew)賦值為0,本質上是將其初始化為空指針(NULL)?,表示該指針當前不指向任何有效的函數。

0在指針上下文中等價于NULL(標準庫中通常定義為((void*)0)),表示無指向目標

例如:g_tUart0.SendBefor = 0; 等價于 g_tUart0.SendBefor = NULL;,表明該回調函數當前未設置。

2.3 關鍵字Volatile

    • 禁止編譯器優化?:

      編譯器在優化代碼時可能將變量值緩存在寄存器中(假設其未被修改)。volatile強制每次訪問變量時直接讀寫內存地址,確保獲取最新值。

  • ?應對“外部修改”??:

    在嵌入式系統中,以下場景需用volatile

    • ?硬件寄存器?(如串口狀態寄存器):值可能被硬件自動更新。

    • ?中斷共享變量?:主程序與中斷服務程序(ISR)共同訪問的變量(如usRxCount)。

    • ?多任務共享變量?:在RTOS中,多個任務間共享的變量。

  • ?在結構體中的應用?

    結構體中usTxWriteusRxCount等成員用__IO修飾,是因為:

    • 它們可能被中斷服務程序修改?(如接收數據時更新指針)。

    • 主循環需實時感知其變化?(如判斷是否有新數據)。

本質就是?硬件寄存器(如串口狀態寄存器)通常被映射到特定的物理內存地址,即 ?內存映射I/O(Memory-Mapped I/O)?,?也就是硬件設計時將串口控制器的寄存器(如STM32的狀態寄存器 USART_SR、數據寄存器 USART_DR)分配固定的物理地址(如USART_DR寄存器地址 0x40004400)程序通過讀寫這些內存地址,等同于直接操作硬件寄存器。

之前我們文章中也說明了,CPU中包含通用數據寄存器,并且還是循環使用的,我覺得在這里可以銜接起來理解,用于暫存運算數據(如 MOV R0, [R1] 將內存數據加載到寄存器R0),這樣就穿起來了。

而對于有些硬件寄存器是外設的物理存儲單元,與CPU寄存器無關,就是上面這一段說的如串口狀態寄存器通常被映射到特定的物理內存地址,這個如何映射的過程,我覺得暫時可以先不用深究,因為觸及到芯片核心了,并且之前我也有在文章中提到。

那么知道了上面的知識,我們才能理解關鍵字volatile具體是啥意思。想想一下我們的應用場景,假設我們的串口在很快的速度發送數據,我們使用數組或者鏈表、隊列去接收數據,然后正常的流程是CPU的通用寄存器通過串口的硬件寄存器獲取的數據存到R0,然后再進行處理,這樣就會有一個問題,串口數據很快,因為CPU需要轉手的原因存在一種情況這邊跟不上接受的速度,可能會導致部分數據混亂或者時序出問題。

總結一下就是下面的情況:

  • 緩存到寄存器?:假設狀態寄存器值不變,將首次讀取的結果緩存到CPU寄存器,后續讀取直接復用緩存值(而非重新訪問內存地址)。

  • ?刪除“冗余”操作?:若多次寫入同一寄存器(如循環中寫數據寄存器),編譯器可能合并為最后一次寫入(認為中間寫入無效)。

程序無法感知硬件實時狀態變化,例如:

  • 等待串口數據時,因狀態寄存器 RXNE 位未被更新,陷入死循環。

  • 發送數據時,因寫入操作被合并,實際只發送最后一字節。

那么這個時候關鍵字就應運而生,直接禁用緩存,CPU通過內存訪問指令?(如LDR)直接操作硬件寄存器,而非將數據復制到CPU寄存器后操作。

此前也有分析過這個地方, 就是關于按鍵信息的標志位,也是通過硬件獲取的,那么如果沒有使用關鍵字就會導致在編譯的時候被優化掉。

?成員類別??成員名??功能說明?
?通信配置?Com標識串口號(如COM1),用于選擇物理外設。
?緩沖區管理?*pTxBuf指向發送緩沖區的指針,存儲待發送的數據。
*pRxBuf指向接收緩沖區的指針,存儲已接收的數據。
usTxBufSize發送緩沖區總容量(單位:字節)。
usRxBufSize接收緩沖區總容量(單位:字節)。
?指針與計數器?usTxWrite發送緩沖區寫入位置索引(下次寫入的位置)。
usTxRead發送緩沖區讀取位置索引(下次發送的位置)。
usTxCount待發送數據的剩余字節數?(= usTxWrite - usTxRead)。
usRxWrite接收緩沖區寫入位置索引(新數據存儲位置)。
usRxRead接收緩沖區讀取位置索引(用戶已讀取位置)。
usRxCount接收緩沖區中未讀取的新數據字節數?(= usRxWrite - usRxRead)。
?回調函數?SendBefore()發送前回調(用于切換RS485為發送模式)。
SendOver()發送完成回調(用于切換RS485為接收模式)。
ReciveNew(_byte)收到單字節數據時觸發,用于實時處理或協議解析。

2.4 隊列結構體數據

在創建不同結構體隊列的時候,原本是想使用隊列通用函數統一管理,但是發現在通用管理中,我們固定了該數據結構體的類型,這樣就導致如果使用不同的結構體就會很麻煩。除非我們在通用結構體中盡可能的廣泛包含對應的數據類型。這樣似乎就可能導致冗余?因為本身我們想通過通用隊列降低盡可能多的語法糖,但是反而會增加。

仔細分析隊列處理函數,我們可以發現并沒有很復雜的邏輯,換句話會說,我們直接實現相關函數也不是不可以。其實使用隊列主要就是對數據的兩次判斷,一次是判空,一次是判滿,

判空指的是:讀的速度很快,接受的很慢。

判滿指的是:讀的速度或者處理的速度比較慢,接收的就很快。

也就是說在裝填的時候,我們怕隊列滿,所以需要判滿。
在讀取的時候,我們怕隊列空,所以需要判空。

對于使用隊列作為數據緩沖,是嵌入式開發中最常見的形式。但在超高吞吐量(雙緩沖)極低延遲(無鎖緩沖)或**極簡需求(靜態變量)**時需選用替代方案。

先進先出(FIFO) ,First-in First-out。

隊列數據必須包含四個成員:
隊頭索引、隊尾索引、隊列長度、隊列緩存數組,其他的可以根據自行需要進行適當擴展。

并且在使用的時候必須要進行隊列判滿和判空 判斷。

緩沖區不是免檢區。

  • 數據完整性的保障?

    • ?隊列滿時寫入?:若不判斷隊列滿狀態,新數據會覆蓋未處理的舊數據,導致數據丟失(如傳感器實時數據流被覆蓋)。

    • ?隊列空時讀取?:若未判斷空狀態,可能讀取無效數據或隨機內存值,引發程序邏輯錯誤。

  • ?資源沖突與系統穩定性?

    • ?緩沖區溢出?:持續寫入未判滿會導致緩沖區溢出,可能破壞相鄰內存區域(如棧溢出),造成系統崩潰。

    • ?多線程/中斷場景?:在中斷服務程序(ISR)中,若未同步判滿/空邏輯,可能因競爭條件(Race Condition)引發數據錯亂。

  • ?性能與效率優化?

    • ?避免無效操作?:判空可跳過無意義的出隊操作,減少CPU浪費;判滿可觸發流控機制(如暫停生產者線程),避免忙等待。

在C語言中,?取模(Modulo)和取余(Remainder)本質上是同一個操作,均使用 % 運算符實現,且語言標準未明確區分兩者。但在處理負數時,C語言的取余行為與數學上的模運算存在差異。也就是需要手動去處理這個取模和取余的區別。因為取模必須為正。

在正數的時候取模和取余是沒有任何區別的。因為都是正數,不存在有什么正負號區別。

C語言取余規則(%運算符)

符號規則?:余數的符號始終與被除數(第一個操作數)相同,與除數無關。

  • 示例:
    • -10 % 3 = -1(被除數 -10 為負 → 結果負)
    • 10 % -3 = 1(被除數 10 為正 → 結果正)
    • -10 % -3 = -1(被除數 -10 為負 → 結果負)

模運算是得到的結果是非負的。
![[Pasted image 20250717150958.png]]
所以在負數取模和取余是有區別的

![[Pasted image 20250717151027.png]]

模運算一定是正的結果。

取余運算要根據被除數正負號來確定。

模運算或者取余對于正數來說可以回到起點,這樣就形成了一種將線性數組映射為環形結構,相當于原本是一個線性的可能需要無線遞增的數組,當我定義了兩個指針以后,尾指針或者是頭指針遍歷到最后一個以后,我取模運算,這樣相當于是數組的下標又變成了零,這樣就又可以重新填充數據或者是覆蓋原來數據,等于可以循環使用這個數組。這是因為數學的取模運算實現了循環。也就是這句話:”循環隊列通過模運算將線性數組映射為環形結構。“

何為映射,描述了兩個集合元素之間的一種定向對應關系。循環隊列通過模運算將線性數組映射為環形結構,應該怎么理解這個映射?

本質是通過數學同余關系在邏輯上實現索引的循環回繞,從而用普通數組模擬環形存儲。

模運算(a % n)的核心性質是將任意整數映射到范圍 [0, n-1] 的同余類中。

  • ?索引回繞公式?:
    • 向后移動:新索引 = (當前索引 + 步長) % 數組長度
    • 向前移動:新索引 = (當前索引 - 步長 + 數組長度) % 數組長度
  • ?示例?(數組長度 n=5):
    • 當前索引 4,向后移動一步:(4+1) % 5 = 0(回到數組起點)
    • 當前索引 0,向前移動一步:(0-1+5) % 5 = 4(跳至數組末尾)

在實際使用過程中還會有一些問題:
假如我們設計的數組長度是10,那么其實使用數組下標訪問的時候是:09,那么如果我們訪問到最后一個的試試其實是a[9],那么使用這個數字進行取余或者取模操作得到的還是9,并不會回到原點,因此就需要將我們的idex手動+1取余操作。或者從另外一個角度,我們第一次訪問的肯定是0位置這個數據,但是接下來就需要訪問1這個位置的數據,好像不對這樣想~,不管如果是單純的回到原點都是可以的。

但是另外一點解決不了,那就是重合的時候不能區分哪一種情況。

第一種是讀的速度追上寫的速度,這樣就會造成空。

第二種是寫的速度追上讀的速度,這樣就會造成滿。

無外乎這兩種情況,所以要根據這兩個情況進行分析。

循環隊列分析及應用-CSDN博客

在這里插入圖片描述

在分析讀的速度追上寫的速度的時候,此時的數組一定是有很多的空余空間的,所以寫的下一位一定是空的。

在分析寫的速度追上讀的速度的時候,此時的數組一定是沒有剩余空間了,并且此時兩個數組的下標是重合的。那么在下標重合之前一定有一個動作是寫位置和讀位置有一個空白間隔。那么這個==寫后面有一個空白位置其實就是和上一個讀的速度追上寫的速度情況保持了一致,也就是能否在這個情況下進行分析,從而找到區別這兩種情況的辦法。
為什么要這樣,我們的目的是控制變量法,就是區分相同情況的兩個事件,那么就一定需要找到他們兩個事件的共同點,從而在共同點的情況下去分析區別這兩個情況的,本例子的共同點就是:
寫后面有一個空白位置==。

在第一種情況下,大前提一定是在讀數據的時候觸發的,那么此時只要滿足


QueueStatus_t QueuePop(QueueType_t *queue, uint8_t *pdata)
{if(queue->head == queue->tail){return QUEUE_EMPTY;}*pdata = queue->buffer[queue->head];queue->head = (queue->head + 1) % queue->size;return QUEUE_OK;
}

我們不用關心寫后面的空白位置,因為在這種空的情況下是一定滿足的,所以只需要這樣判斷那么一定就是該數據要空了。

接著在考慮第二種情況,此時的大前提一定是在寫數據的時候,這個時候注意了,寫數據的時候如果我們不干預,他會一只寫,畢竟任何限制都沒有無外乎進行循環操作。就算寫滿了空閑位置,還沒有來得及讀,一樣會繼續寫,覆蓋掉未處理的時候,只要不加限制。所以這種情況我們要人為的制造出來一個:寫后面有一個空白位置,因為只有這個保持一致,我們才能和第一種情況區分,否則沒有同維度下的判斷,我覺得類比是沒有意義的。

所以我們的代碼寫的思路首先是將寫數組的下標進行自增1。此時index指向的就是下一個當前寫數據的 下一個位置。

uint32_t index = (queue->tail + 1) % queue->size;

由于我們認為規定了,在寫數據的時候,相對于當前位置的下一個位置必須為空,這個寫有意義,否則就是沒意義的。那么相反當在寫數據的時候,相對于當前位置的下一個位置是當前正在讀數據的位置時候,就表明此時數組已經滿了。所以我們就找他的想反面,那我們為什么不直接找“在寫數據的時候,相對于當前位置的下一個位置必須為空”這種情況吶,因為這個情況不好把握呀,很多種情況都滿足,也就是說寫的時候不好控制,但是我們可以控制溢出條件,因為溢出條件只有一種,那就是“那么相反當在寫數據的時候,相對于當前位置的下一個位置是當前正在讀數據的位置時候,就表明此時數組已經滿了” 所以才有了這段代碼

    uint32_t index = (queue->tail + 1) % queue->size;if (index == queue->head){return QUEUE_OVERLOAD;}queue->buffer[queue->tail] = data;queue->tail = index;return QUEUE_OK;

這個條件其實就是表明我現在寫數據的位置已經到了我們規定不能寫數據的位置,所以要退出函數。

如果覺得我的內容對您有幫助,希望不要吝嗇您的贊和關注,您的贊和關注是我更新優質內容的最大動力。



專欄介紹

《嵌入式通信協議解析專欄》
《PID算法專欄》
《C語言指針專欄》
《單片機嵌入式軟件相關知識》
《FreeRTOS源碼理解專欄》
《嵌入式軟件分層架構的設計原理與實踐驗證》



文章源碼獲取方式:
如果您對本文的源碼感興趣,歡迎在評論區留下您的郵箱地址。我會在空閑時間整理相關代碼,并通過郵件發送給您。由于個人時間有限,發送可能會有一定延遲,請您耐心等待。同時,建議您在評論時注明具體的需求或問題,以便我更好地為您提供針對性的幫助。

【版權聲明】
本文為博主原創文章,遵循 CC 4.0 BY-SA 版權協議。這意味著您可以自由地共享(復制、分發)和改編(修改、轉換)本文內容,但必須遵守以下條件:
署名:您必須注明原作者(即本文博主)的姓名,并提供指向原文的鏈接。
相同方式共享:如果您基于本文創作了新的內容,必須使用相同的 CC 4.0 BY-SA 協議進行發布。

感謝您的理解與支持!如果您有任何疑問或需要進一步協助,請隨時在評論區留言,筆者一定知無不言,言無不盡。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/92464.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/92464.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/92464.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

使用Navicat備份數據庫MySQL、PostGreSQL等

Navicat 支持多種數據庫系統,可通過手動或自動方式進行數據備份,整個過程還是相對簡單且直觀,比自己敲命令行方便多了。一、備份步驟1.1、手動備份1、打開Navicat并連接數據庫:首先,啟動Navicat并連接到您的MySQL數據庫…

Web3: 用ERC-1400革新公司股權激勵

大家好!今天,我們來聊一個非常酷的話PEG話題:如何利用Web3技術,特別是ERC-1400證券型代幣標準,來革新傳統的公司股權激勵模式。 大家是否想過,派發給員工的期權或限制性股票(RSU)可以…

【Python 高頻 API 速學 ④】

一、為什么是這 4 個? 列表(list)是 Python 最常用的可變序列, 90 % 的操作可以濃縮成 「增、并、刪、排」 四個字, 而這四個字正好對應 append / extend / pop / sort。二、四劍客一覽方法作用原地?返回值…

K8S的POD數量限制

#k8s-v1.11.11.查詢當前節點的最大pod數kubectl describe nodes | grep pods2.編輯配置文件把單臺的pod數量調到150個vim /etc/systemd/system/kubelet.service #添加最大數量--maxPods: 1503.加載配置重啟服務systemctl daemon-reload systemctl restart kubelet#k8s-v1.21.41…

OpenAI開源大模型 GPT-OSS 開放權重語言模型解析:技術特性、部署應用及產業影響

注:此文章內容均節選自充電了么創始人,CEO兼CTO陳敬雷老師的新書《GPT多模態大模型與AI Agent智能體》(跟我一起學人工智能)【陳敬雷編著】【清華大學出版社】 清華《GPT多模態大模型與AI Agent智能體》書籍配套視頻課程【陳敬雷…

CSS--后端也有自己的CSS要學

CSS,即Cascading Style Sheets,它描述了網頁的表現與展示效果 為了演示CSS,我寫了一個簡單的index.html 為了使用控制變量法,一開始我先不寫style.css文件的內容 右鍵在默認瀏覽器里查看頁面,看看效果 1-選擇器 根據標簽名進行匹配,所以也叫元素選擇器 頁面效果: 根據…

Docker swarm 常用的命令集合

#docker swarm## 初始化單節點Swarm docker swarm init# 部署測試服務 docker service create --name web --publish 8080:80 --replicas 3 nginx:alpine# Manager節點初始化(指定IP) docker swarm init --advertise-addr 192.168.1.100# 獲取加入令牌 M…

231. 2 的冪

Problem: 231. 2 的冪 文章目錄思路解題過程復雜度Code思路 2的冪 n 的二進制只有一個1,而 n - 1的二進制則是把 n 的二進制1變0, 0變1。 例:2^24100,34-1011. 解題過程 n & n - 1 0 復雜度 時間復雜度: O(1)O(1)O(1)空間復雜度: O(1)O(1)O(1) Co…

淺嘗AI輔助C轉Verilog方法

一、常規算法模塊的開發流程日常芯片開發工作中,挺多看工作是把C語言轉verilog。例如ISP的代碼,都很先由算法進行C model的開發,驗證完性能后,輸出算法原理文檔和c代碼;數字設計接手,把C語言轉換為verilog代…

Redis分布式鎖詳解:原理、實現與實戰案例

目錄 1. 什么是分布式鎖? 分布式鎖的核心要求 2. 基于Redis的分布式鎖實現方案 (1)基礎方案:SETNX EXPIRE (2)優化方案:SET NX PX(原子性加鎖) (3&…

【能碳建設1】用AI+開源打造物聯網+能碳管理+交易SaaS系統的最短路徑實施指南

摘要 本指南為技術小白設計,目標是在最短時間內利用AI工具與開源系統,獨立完成一套物聯網平臺 + 能碳管理平臺 + 碳交易系統的SaaS最小可用版本(MVP),并可后續擴展。流程分為目標定義、技術選型、環境搭建、核心功能開發、SaaS化、多租戶、上線運維等環節,按天推進,每步…

CVPR中深度學習新范式:通用性、魯棒性與多模態的創新突破

來gongzhonghao【圖靈學術計算機論文輔導】,快速拿捏更多計算機SCI/CCF發文資訊~分享一個深度學習領域正在迅速升溫的前沿方向:通用性與魯棒性的深度神經網絡架構創新。隨著大模型在視覺、文本乃至多模態任務中的廣泛應用,體現出深…

Vue3 學習教程,從入門到精通,Vue 3 + Tailwind CSS 全面知識點與案例詳解(31)

Vue 3 Tailwind CSS 全面知識點與案例詳解一、Vue 3 核心語法知識點 1. Vue 3 基礎 創建 Vue 3 項目 使用 Vite 創建項目:npm create vuelatest # 選擇需要的特性(如 TypeScript、Vue Router)響應式數據 使用 ref 和 reactive:im…

Android中RecyclerView基本使用

一、RecyclerView 核心概念1. 基本組件關系2. 核心組件作用Adapter:數據與視圖的橋梁LayoutManager:控制布局方式(線性/網格/瀑布流)ViewHolder:緩存視圖組件ItemDecoration:添加分割線等裝飾ItemAnimator&…

A100用transformers推理gpt-oss

A100本地用transformers推理gpt-oss GPT-oss試用 gpt-oss有兩個原生配置是目前(2025-8-8)Ampere系列顯卡不支持的,分別是默認的MXFP4量化,以及Flash-attn V3。tranformers推理是比較慢的,可以用于研究模型本身&#x…

虛擬手機號工具使用

背景:注冊部分國外應用時需要國外手機號驗證,例如在注冊cursor時需要國外手機號 解決:使用虛擬手機號網頁進行驗證 https://temp-number.com/ 選擇自己需要的國家 選擇一個手機號 復制手機號到自己的app注冊頁面 并發送消息,然后…

【線程池】壓測確定線程池合適的參數

【線程池】壓測確定線程池合適的參數【一】案例說明【二】明確線程池核心參數及優化目標【1】線程池核心參數(需壓測驗證的關鍵參數)【2】優化目標【三】壓測前準備【1】環境搭建【2】線程池初始配置(基于經驗值)【3】壓測工具與監…

GPT OSS 雙模型上線,百度百舸全面支持快速部署

GPT OSS 是 OpenAI 推出的重量級開放模型,專為強推理能力、智能體任務及多樣化開發場景設計,標志著大模型在開放性與實用性上的重要突破。該系列包含兩款高性能模型:參數規模為 117B 的 GPT?OSS?120B 和 21B 的 GPT?OSS?20B。二者皆采用 …

C++高頻知識點(十七)

文章目錄81. 你對智能指針的了解82. 一元、二元仿函數的區別和使用背景一元仿函數二元仿函數83. 描述Linux下文件刪除的原理84. 什么是菱形繼承?有什么問題,怎么解決?解決菱形繼承問題85. IO多路復用是什么?selectpollepollselect…

如何優雅的使用進行參數校驗

在spring里面有一個注解 Validated可以在方法的入參里面這樣寫//方法 getActivityFlag(RequestBody Validated QueryActivityDto queryActivityDto) //參數詳情NotBlank(message "userId不能為空")private String userId;NotNull(message "storeId不能為空&q…