實(shí)現(xiàn)posix消息隊(duì)列示例分享
mqueue.h
//
// mqueue.h
// UNIX_C
//
// Created by 周凱 on 14-2-9.
// Copyright (c) 2014年 zk. All rights reserved.
//
#ifndef __PS_MQUEUE_H
#define __PS_MQUEUE_H
#include <unistd.h>
#include <sys/types.h>
typedef struct mq_info *mqd_t;
typedef struct mq_attr mq_attr;
#ifdef __cplusplus
extern "C" {
#endif
mqd_t mq_open(const char *name, int flag, .../*mode_t mode, struct mq_attr *attr*/);
int mq_close(mqd_t mqdes);
int mq_unlink(const char *name);
int mq_getattr(mqd_t mqdes,mq_attr *attr);
int mq_setattr(mqd_t mqdes,const mq_attr *attr,mq_attr *old);
int mq_send(mqd_t mqdes,const char *ptr,size_t len,unsigned int prio);
int mq_receive(mqd_t mqdes,char *ptr,size_t len,unsigned int *priop);
//
void mq_info_test(mqd_t mqdes);
#ifdef __cplusplus
}
#endif
#endif
多進(jìn)程,多線程創(chuàng)建同一個(gè)隊(duì)列測(cè)試
#include <wrap_ext.h>
#include <mqueue.h>
void *create_mq(void *name){
mqd_t mq;
mq = mq_open("/tmp/mqfile", O_CREAT,FILE_MODE,0);
if (mq == (mqd_t) -1) {
err_ret(errno, "mq_open() error");
return 0;
}
mq_info_test(mq);
mq_close(mq);
return 0;
}
int main(){
mq_unlink("/tmp/mqfile");
if (Fork() == 0) {
create_mq("/tmp/mqfile");
exit(0);
}
Create_detach_thread(create_mq, "/tmp/mqfile");
Create_detach_thread(create_mq, "/tmp/mqfile");
sleep(50);
//mq_unlink("/tmp/mqfile");
return 0;
}
測(cè)試結(jié)果
create,start create...
create,start init...
exists,wait get...
exists,wait get...
create,end init...
mq_hdr.mqh_free:116 bytes
msghdr size:268 bytesmap file size:3332 bytes
next msg offset and msg length:
[384,0];[652,0];[920,0];[1188,0];[1456,0];
[1724,0];[1992,0];[2260,0];[2528,0];exists,start get...
[2796,0];
[3064,0];[0,0];
end,start get...
exists,start get...
mq_hdr.mqh_free:116 bytes
msghdr size:268 bytesmap file size:3332 bytes
next msg offset and msg length:
[384,0];[652,0];[920,0];[1188,0];[1456,0];
[1724,0];[1992,0];[2260,0];[2528,0];[2796,0];
[3064,0];[0,0];
end,start get...
mq_hdr.mqh_free:116 bytes
msghdr size:268 bytesmap file size:3332 bytes
next msg offset and msg length:
[384,0];[652,0];[920,0];[1188,0];[1456,0];
[1724,0];[1992,0];[2260,0];[2528,0];[2796,0];
[3064,0];[0,0];
Program ended with exit code: 0
屬性設(shè)置、獲取測(cè)試
#include <wrap_ext.h>
#include <mqueue.h>
void print_attr(mq_attr *attr){
assert(attr);
err_msg(" mq_attr mq_flag:0x%0x"
" mq_curmsgs:%d"
" mq_msgsize:%d"
" mq_maxmsg:%d"
,attr->mq_flags
,attr->mq_curmsgs
,attr->mq_msgsize
,attr->mq_maxmsg);
}
void *create_mq(void *name){
pthread_t tid;
mq_attr attr,old;
mqd_t mq;
int flag;
flag = O_CREAT;
tid = pthread_self();
if ((long)tid % 2 != 0) {
flag = O_NONBLOCK;
}
mq = mq_open("/tmp/mqfile", flag | O_CREAT,FILE_MODE,0);
if (mq == (mqd_t) -1) {
err_ret(errno, "mq_open() error");
return 0;
}
if ((long)tid % 2 == 0) {
attr.mq_flags = O_NONBLOCK;
mq_setattr(mq, &attr, &old);
}
else
mq_getattr(mq, &old);
print_attr(&old);
//mq_info_test(mq);
mq_close(mq);
return 0;
}
int main(){
pid_t pid;
mq_unlink("/tmp/mqfile");
if ((pid=Fork()) == 0) {
create_mq("/tmp/mqfile3");
Create_detach_thread(create_mq, "/tmp/mqfile1");
Create_detach_thread(create_mq, "/tmp/mqfile2");
sleep(1);
exit(0);
}
Create_detach_thread(create_mq, "/tmp/mqfile1");
Create_detach_thread(create_mq, "/tmp/mqfile2");
create_mq("/tmp/mqfile3");
wait(0);
sleep(5);
//mq_unlink("/tmp/mqfile");
return 0;
}
測(cè)試注冊(cè)通知規(guī)則
#include <wrap_ext.h>
#include <mqueue.h>
int main(){
pid_t pid;
Init_wait();
mqd_t mq;
sigevent_t sige;
mq_unlink("/tmp/mqfile");
mq = mq_open("/tmp/mqfile", O_CREAT,FILE_MODE,0);
Signal(SIGCHLD, SIG_DFL);
if (mq == (mqd_t) -1) {
err_sys(errno, "mq_open() error");
}
if ((pid=Fork()) == 0) {
if (mq_notify(mq, &sige) == -1)
err_ret(errno, "mq_notify() error");
Tell_parent();
Wait_parent();
End_wait();
sleep(1);
exit(0);
}
Wait_child();
/*子進(jìn)程已注冊(cè),測(cè)試是否能注冊(cè)、取消通知*/
if (mq_notify(mq, 0) == -1)
err_ret(errno, "mq_notify() error");
if (mq_notify(mq, &sige) == -1)
err_ret(errno, "mq_notify() error");
Tell_child(pid);
End_wait();
wait(0);
sleep(1);
/*子進(jìn)程已結(jié)束,測(cè)試是否能注冊(cè)通知*/
if (mq_notify(mq, &sige) == -1)
err_ret(errno, "mq_notify() error");
//mq_unlink("/tmp/mqfile");
return 0;
}
mqueue.c
//
// File.c
// UNIX_C
//
// Created by 周凱 on 14-2-9.
// Copyright (c) 2014年 zk. All rights reserved.
//
#include "mqueue.h"
#include <wrap_ext.h>
#if !defined(_LINUX_)
#define va_mode_t int
#else
#define va_mode_t mode_t
#endif
typedef struct mq_info mq_info;
typedef struct mq_hdr mq_hdr;
//typedef struct mq_attr mq_attr;
typedef struct mq_msg mq_msg;
struct mq_hdr{
mq_attr mqh_attr;
long mqh_head;
long mqh_free;
pthread_cond_t mqh_conn;
pthread_mutex_t mqh_mutex;
sigevent_t mqh_sigevent;
pid_t mqh_pid;
};
struct mq_msg{
long msg_next;/*從映射內(nèi)存的地址起,到下一個(gè)消息的偏移值*/
ssize_t msg_len;
int msg_prio;
};
struct mq_info{
mq_hdr *mqi_hdr;
long long mqi_magic;
int mqi_flag;
};
#define MQ_MAXMSG 12
#define MQ_MSGSIZE 256
#define MQ_MAGIC 0x9235167840
/*
防止以下情況:
一個(gè)進(jìn)程或線程以創(chuàng)建模式打開(kāi)一個(gè)隊(duì)列,
隨后CPU切換當(dāng)前進(jìn)程或線程到另一個(gè)正
在打開(kāi)此前創(chuàng)建的隊(duì)列,但是該隊(duì)列并未
初始化完畢,故使用一個(gè)記錄鎖加一個(gè)線
程鎖,進(jìn)行同步。
注:
該實(shí)現(xiàn)不是異步調(diào)用安全,即不能在信號(hào)處理函數(shù)中調(diào)用隊(duì)列打開(kāi)(創(chuàng)建)函數(shù)
*/
#define MQ_LOCK_FILE "/tmp/mq_lock_file"
static struct mq_attr def_attr = {0,MQ_MAXMSG,MQ_MSGSIZE,0};
static pthread_once_t __mq_once = PTHREAD_ONCE_INIT;
static pthread_mutex_t __mq_lock;
static pthread_key_t __mq_key;
static void __mq_once_init();
static int __mq_get_filelock();
static void *__mq_mmap_file(int fd,mq_attr *attr);
static int __mq_init_mmap(void *ptr,mq_attr *attr);
static void __mq_unmap(const char *name,void *ptr);
static void __mq_once_init(){
pthread_mutexattr_t mattr;
Pthread_mutexattr_init(&mattr);
Pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_RECURSIVE);
Pthread_mutex_init(&__mq_lock, &mattr);
Pthread_mutexattr_destroy(&mattr);
Pthread_key_create(&__mq_key, 0);
}
static int __mq_get_filelock(){
int fd,tmp;
Pthread_mutex_lock(&__mq_lock);
if ((fd = (int)Pthread_getspecific(__mq_key)) == 0) {
fd = open(MQ_LOCK_FILE, O_CREAT | O_EXCL | O_WRONLY, FILE_MODE);
if (fd == -1 && errno != EEXIST)
err_sys(errno, "mq_open(),__mq_get_filelock() error");
else
fd =Open(MQ_LOCK_FILE, O_WRONLY, 0);
if (fd == 0) {
tmp = Open(MQ_LOCK_FILE, O_WRONLY, 0);
close(fd);
fd = tmp;
}
Pthread_setspecific(__mq_key, (void*)fd);
}
Pthread_mutex_unlock(&__mq_lock);
return fd;
}
static void *__mq_mmap_file(int fd,mq_attr *attr){
size_t filesize;
void *ptr;
if (attr == 0) {
attr = &def_attr;
}
if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
errno = EINVAL;
return MAP_FAILED;
}
filesize = sizeof(mq_hdr)+(sizeof(mq_msg)+ALIGN_VAL(attr->mq_msgsize, sizeof(long)))*attr->mq_maxmsg;
if(lseek(fd, filesize - 1, SEEK_SET)<0)
return MAP_FAILED;
if(write(fd,"",1)!=1)
return MAP_FAILED;
ptr = mmap(NULL, filesize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
return ptr;
}
static void __mq_unmap(const char *name,void *ptr){
size_t filesize;
stat_t fstat;
assert(name);
if (stat(name, &fstat) == -1) {
return;
}
filesize = (size_t)fstat.st_size;
unlink(name);
if (ptr == MAP_FAILED) {
return;
}
munmap(ptr, filesize);
return;
}
static int __mq_init_mmap(void *ptr,mq_attr *attr){
char *tmp;
size_t index,i;
int flag;
mq_hdr *mqhdr;
mq_msg *mqmsg;
pthread_condattr_t cattr;
pthread_mutexattr_t mattr;
assert(ptr);
if (attr == 0) {
attr = &def_attr;
}
if (attr->mq_maxmsg <= 0 || attr->mq_msgsize <= 0) {
errno = EINVAL;
return -1;
}
tmp = ptr;
mqhdr = (mq_hdr*)tmp;
mqhdr->mqh_attr.mq_flags = 0;
mqhdr->mqh_attr.mq_curmsgs = 0;
mqhdr->mqh_attr.mq_maxmsg = attr->mq_maxmsg;
mqhdr->mqh_attr.mq_msgsize = attr->mq_msgsize;
flag = pthread_condattr_init(&cattr);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_condattr_setpshared(&cattr, PTHREAD_PROCESS_SHARED);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_cond_init(&mqhdr->mqh_conn, &cattr);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_condattr_destroy(&cattr);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_mutexattr_init(&mattr);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_mutexattr_setpshared(&mattr, PTHREAD_PROCESS_SHARED);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_mutex_init(&mqhdr->mqh_mutex, &mattr);
if (flag) {
errno = flag;
return -1;
}
flag = pthread_mutexattr_destroy(&mattr);
if (flag) {
errno = flag;
return -1;
}
index = mqhdr->mqh_free = sizeof(mq_hdr);
mqmsg = (mq_msg*)(tmp+index);
for (i = 0; i < attr->mq_maxmsg - 1; i++) {
mqmsg->msg_next = sizeof(mq_msg) + ALIGN_VAL(attr->mq_msgsize, sizeof(long)) + index;
index = mqmsg->msg_next;
mqmsg ++;
//mqmsg = (mq_msg*)(tmp+index);
}
mqmsg->msg_next = 0;
return 0;
}
mqd_t mq_open(const char *name,int flag,...){
int fd, nonblock, lockfile_fd, err;
void *ptr;
mq_attr *mqattr;
mqd_t mqdesc;
stat_t filestat;
debug_assert("Invalid pointer", "mq_open()", name);
Pthread_once(&__mq_once, __mq_once_init);
nonblock = flag & O_NONBLOCK;
mqattr = NULL;
mqdesc = NULL;
ptr = MAP_FAILED;
__again:
if (flag & O_CREAT) {
va_list vp;
mode_t mode;
/*分析可變參數(shù)*/
va_start(vp, flag);
mode = va_arg(vp, va_mode_t);
mqattr = va_arg(vp, mq_attr *);
va_end(vp);
Pthread_mutex_lock(&__mq_lock);
lockfile_fd = __mq_get_filelock();
write_lock_wait(lockfile_fd, SEEK_SET, 0, 0);
fd = open(name, flag | O_CREAT | O_EXCL | O_RDWR, mode);
if (fd < 0) {
/*如果指定了O_EXCL,并且文件已存在,則等待其他進(jìn)程或線程完成初始化*/
if (errno == EEXIST && (flag & O_EXCL) == 1) {
return (mqd_t)-1;
}
goto __exists_wait_init;
}
/*初始化內(nèi)存映射文件*/
err_msg("create,start init...");
/*初始化映射文件大?。ㄗ⒁獗仨毷刮募L(zhǎng)度達(dá)到映射的大?。?,且映射文件到內(nèi)存*/
ptr = __mq_mmap_file(fd, mqattr);
//sleep(1);
if (ptr == MAP_FAILED) {
goto __err;
}
/*初始化映射內(nèi)存的內(nèi)容*/
if (__mq_init_mmap(ptr, mqattr) < 0) {
goto __err;
}
mqdesc = (mqd_t)calloc(1, sizeof(mq_hdr));
if (mqdesc == 0) {
goto __err;
}
mqdesc->mqi_hdr = (mq_hdr*)ptr;
mqdesc->mqi_flag = nonblock;
mqdesc->mqi_magic = MQ_MAGIC;
err_msg("create,end init...");
file_unlock(lockfile_fd, SEEK_SET, 0, 0);
Pthread_mutex_unlock(&__mq_lock);
return mqdesc;
}
__exists_wait_init:
fd = open(name, O_RDWR, 0);
if (fd < 0 ) {
if (errno == ENOENT && (flag & O_CREAT)) {
goto __again;
}
goto __err;
}
err_msg("exists,start get...");
if (stat(name, &filestat) == -1) {
if (errno == ENOENT && (flag & O_CREAT)) {
goto __again;
}
goto __err;
}
ptr = mmap(0, (size_t)filestat.st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (ptr == MAP_FAILED) {
goto __err;
}
mqdesc = (mqd_t)calloc(1, sizeof(mq_hdr));
if (mqdesc == 0) {
goto __err;
}
mqdesc->mqi_hdr = (mq_hdr*)ptr;
mqdesc->mqi_flag = nonblock;
mqdesc->mqi_magic = MQ_MAGIC;
close(fd);
file_unlock(lockfile_fd, SEEK_SET, 0, 0);
Pthread_mutex_unlock(&__mq_lock);
err_msg("end,start get...");
return mqdesc;
__err:
file_unlock(lockfile_fd, SEEK_SET, 0, 0);
Pthread_mutex_unlock(&__mq_lock);
err = errno;
__mq_unmap(name, ptr);
close(fd);
if (mqdesc)
free(mqdesc);
errno = err;
return (mqd_t)-1;
}
int mq_close(mqd_t mqdes){
size_t filesize;
mq_attr *mattr;
int flag;
assert(mqdes);
if (mqdes->mqi_magic != MQ_MAGIC) {
errno = EBADF;
return -1;
}
mattr = &mqdes->mqi_hdr->mqh_attr;
filesize = mattr->mq_maxmsg * (sizeof(mq_msg)* ALIGN_VAL(mattr->mq_msgsize, sizeof(long))) + sizeof(mq_hdr);
flag = munmap((void*)mqdes->mqi_hdr, filesize);
mqdes->mqi_magic = 0;
free(mqdes);
return flag;
}
int mq_unlink(char const *name){
assert(name);
return unlink(name);
}
int mq_getattr(mqd_t mqdes,mq_attr *attr){
int flag;
mq_attr *tmp;
assert(mqdes);
assert(attr);
if (mqdes->mqi_magic != MQ_MAGIC) {
errno = EBADF;
return -1;
}
tmp = &mqdes->mqi_hdr->mqh_attr;
/*防止其他進(jìn)程或線程在改變屬性值*/
flag = pthread_mutex_lock(&mqdes->mqi_hdr->mqh_mutex);
if (flag > 0) {
errno = flag;
return -1;
}
bcopy(&mqdes->mqi_hdr->mqh_attr, attr, sizeof(mq_attr));
attr->mq_flags = mqdes->mqi_flag;
flag = pthread_mutex_unlock(&mqdes->mqi_hdr->mqh_mutex);
if (flag > 0) {
errno = flag;
return -1;
}
return 0;
}
int mq_setattr(mqd_t mqdes,const mq_attr *attr,mq_attr *old){
int flag;
mq_attr *tmp;
assert(mqdes);
assert(attr);
if (mqdes->mqi_magic != MQ_MAGIC) {
errno = EBADF;
return -1;
}
tmp = &mqdes->mqi_hdr->mqh_attr;
/*防止其他進(jìn)程或線程在讀取屬性值*/
flag = pthread_mutex_lock(&mqdes->mqi_hdr->mqh_mutex);
if (flag > 0) {
errno = flag;
return -1;
}
if (old != NULL) {
bcopy(&mqdes->mqi_hdr->mqh_attr, old, sizeof(mq_attr));
old->mq_flags = mqdes->mqi_flag;
}
/*創(chuàng)建后,只有文件標(biāo)識(shí)可以改變*/
//bcopy(attr, &mqdes->mqi_hdr->mqh_attr, sizeof(mq_attr));
/*只有O_NONBLOCK標(biāo)志可以存儲(chǔ)*/
if (attr->mq_flags & O_NONBLOCK) {
mqdes->mqi_flag |= O_NONBLOCK;
}
else {
mqdes->mqi_flag &= ~O_NONBLOCK;
}
flag = pthread_mutex_unlock(&mqdes->mqi_hdr->mqh_mutex);
if (flag > 0) {
errno = flag;
return -1;
}
return 0;
}
int mq_notify(mqd_t mqdes,const struct sigevent *notification){
sigevent_t *old;
pid_t pid;
int flag;
assert(mqdes);
if (mqdes->mqi_magic != MQ_MAGIC) {
errno = EBADF;
return -1;
}
flag = pthread_mutex_lock(&mqdes->mqi_hdr->mqh_mutex);
if (flag > 0) {
errno = flag;
return -1;
}
pid = mqdes->mqi_hdr->mqh_pid;
/*已設(shè)置*/
if (pid != 0) {
/*發(fā)送一個(gè)0信號(hào)給注冊(cè)的進(jìn)程,如果能發(fā)送,或者不能發(fā)送但不是返回沒(méi)有進(jìn)程的錯(cuò)誤(可能權(quán)限不夠),則不能再次注冊(cè)通知*/
/*有效進(jìn)程*/
if (kill(pid, 0) != -1 || errno != ESRCH) {
if (notification == 0) {
if (pid != getpid()) {
errno = EPERM;
flag = -1;
}
else {
mqdes->mqi_hdr->mqh_pid = 0;
flag = 0;
}
}
else {
errno = EBUSY;
flag = -1;
}
goto __return;
}
/*無(wú)效進(jìn)程*/
}
/*未設(shè)置*/
if (notification != 0) {
mqdes->mqi_hdr->mqh_pid = getpid();
old = &mqdes->mqi_hdr->mqh_sigevent;
bcopy(notification, old, sizeof(sigevent_t));
}
flag = 0;
__return:
pthread_mutex_unlock(&mqdes->mqi_hdr->mqh_mutex);
return flag;
}
void mq_info_test(mqd_t mqdes){
size_t i,msgsize,index;
mq_msg *msg;
mq_attr *mattr;
assert(mqdes);
mattr = &mqdes->mqi_hdr->mqh_attr;
msgsize = sizeof(mq_msg) + ALIGN_VAL(mattr->mq_msgsize, sizeof(long));
index = mqdes->mqi_hdr->mqh_free;
err_msg("mq_hdr.mqh_free:%ld bytes\n"
"msghdr size:%u bytes"
"map file size:%u bytes"
, index
, msgsize
, mattr->mq_maxmsg * msgsize + index);
err_msg("next msg offset and msg length:");
msg = (mq_msg*)&((char*)mqdes->mqi_hdr)[index];
for (i = 0; i < mattr->mq_maxmsg; i++) {
fprintf(stderr, "[%ld,%ld];", msg->msg_next, msg->msg_len);
if ((i+1)%5 == 0) {
fprintf(stderr,"\n");
}
msg ++ ;
}
if ((i+1)%5 != 0) {
fprintf(stderr,"\n");
}
return;
}
相關(guān)文章
C 語(yǔ)言關(guān)于聯(lián)合體的相關(guān)知識(shí)
這篇文章主要介紹了C 語(yǔ)言關(guān)于聯(lián)合體的相關(guān)知識(shí),文中講解非常細(xì)致,代碼幫助大家更好的理解學(xué)習(xí),感興趣的朋友可以了解下2020-06-06淺談帶緩沖I/O 和不帶緩沖I/O的區(qū)別與聯(lián)系
下面小編就為大家?guī)?lái)一篇淺談帶緩沖I/O 和不帶緩沖I/O的區(qū)別與聯(lián)系。小編覺(jué)得挺不錯(cuò)的現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-01-01C++11新特性“=default”,“=delete”的使用
=default、=delete 是C++11的新特性,分別為:顯式缺省(告知編譯器生成函數(shù)默認(rèn)的缺省版本)和顯式刪除(告知編譯器不生成函數(shù)默認(rèn)的缺省版本),本文就來(lái)介紹一下如何使用2021-05-05C#如何調(diào)用原生C++ COM對(duì)象詳解
這篇文章主要給大家介紹了C#如何調(diào)用原生C++ COM對(duì)象,在C++中實(shí)現(xiàn)C#的接口。文中通過(guò)示例代碼介紹的很詳細(xì),相信對(duì)大家的理解和學(xué)習(xí)會(huì)有一定的參考借鑒價(jià)值,有需要的朋友們下面來(lái)一起看看吧。2016-12-12C++實(shí)現(xiàn)學(xué)生管理系統(tǒng)示例解析
這篇文章主要介紹了C++實(shí)現(xiàn)學(xué)生管理系統(tǒng)示例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08C++?boost?thread庫(kù)用法詳細(xì)講解
Boost是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱。Boost庫(kù)是一個(gè)可移植、提供源代碼的C++庫(kù),作為標(biāo)準(zhǔn)庫(kù)的后備,是C++標(biāo)準(zhǔn)化進(jìn)程的開(kāi)發(fā)引擎之一,是為C++語(yǔ)言標(biāo)準(zhǔn)庫(kù)提供擴(kuò)展的一些C++程序庫(kù)的總稱2022-11-11dev-c++創(chuàng)建lib(靜態(tài)鏈接庫(kù))文件的實(shí)現(xiàn)步驟
本文主要介紹了dev-c++創(chuàng)建lib(靜態(tài)鏈接庫(kù))文件的實(shí)現(xiàn)步驟,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2022-06-06