Archive

Posts Tagged ‘C’

使用 C# 呼叫 MATLAB Function

九月 10th, 2009

最近在寫一些演算法的程式,經常要在一堆程式和檔案切換來切換去的,跑完數據還要開 MATLAB 畫圖,一直重複這些動作實在是很麻煩,所以把它寫成 Windows Form 用滑鼠點一點就 OK 了,其中繪圖部份就要利用 C# 去 call MATLAB 來作,查了許多資料,發現有很多種方法,但比較簡單方便的應該是用 MATLAB Builder NE for .NET 將 MATLAB 程式編譯成 .NET 可執行的元件。

1. 首先準備好你要 compiler 的 M-file,測試的 M-file 如下(由檔案讀取 x, y 數據曲線圖):


function rmse(file)

data = load(file);
x = data(:,1);
y = data(:,2);

plot(x,y,'LineWidth',1);

xlabel('Iteration');
ylabel('RMS error');

2. 開啟 MATLAB 並在 command windows 輸入:deploytool
新建一個 project,名稱為 rmse。
New Project
選擇 .NET component
.NET component
將 M-file 加入,然後按 Build the project,編譯完成會產生 rmse.dll
Add file

3. 將 .dll 加入 Visual Studio 參考(Reference)
在方案總管右鍵選「加入參考」>「瀏覽」,將剛剛編譯完成的 .dll 以及 MATLAB 安裝目錄底下的 toolbox\dotnetbuilder\bin\win32\v2.0\MWArray.dll 加入。

4. 加入 Namespace
using MathWorks.MATLAB.NET.Arrays;
using rmse;

5. 使用方式
Rmse demo = new Rmse();
MWArray fileName = @"rmse.txt";
demo.rmse(fileName);

demo 範例原始碼下載

※ 如果想在沒安裝 MATLAB 的電腦上執行,需安裝 MATLAB Compiler Runtime (MCR),檔案在安裝目錄的 toolbox\compiler\deploy\win32\MCRInstaller.exe,大小約 150MB

Other, 程式筆記 , , ,

TwSMS 發簡訊 (Linux C 版)

一月 21st, 2008

台灣簡訊(TwSMS)是國內一家線上傳簡訊的服務商,提供文字簡訊、語音簡訊等服務,價格也很合理,最重要的是有提供 API 介面,方便用戶在自己的程式中加入發送簡訊功能,官網已經有提供不少範例(PHP/ASP/JSP/Java/Perl/VB/BCB/Delphi),這邊也有 Ruby 的版本,不過就是沒看到 C 的,所以大略寫了一個 Linux C 版本,打算加入自己的嵌入式專題使用。

TwSMS 提供的 API 很簡單,只要由 HTTP 對 API server 發送 Request 即可,接著 server 就會回傳結果。程式先建立一個 socket 連線,然後發送簡訊,最後再擷取回傳碼檢查是否成功。


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>

int main()
{
	/* TWSMS 相關設定 */
	char *username = "username";   // 帳號
	char *password = "password"; // 密碼
	char *type = "now";         // 發送型態
	char *mobile = "0912xxxxxx"; // 電話
	char *message = "簡訊測試"; // 簡訊內容
	char *encoding = "big5";    // 簡訊內容編碼
	char *popup = "";          // 使用 POPUP 顯示
	char *mo = "";             // 使用雙向簡訊
	char *vldtime = "86400";    // 簡訊有效期限(秒)
	char *dlvtime = "";         // 預約時間

	int sockfd;
	int len = 0;
	char *host = "api.twsms.com";
	char msg[512], MSGData[512], buf[512];
	char *res, *checkRes;
	struct sockaddr_in address;
	struct hostent *hostinfo;

	bzero(&address, sizeof(address));
	hostinfo = gethostbyname(host);
	if (!hostinfo) {
		fprintf(stderr, "no host: %s\n", host);
		exit(1);
	}
	address.sin_family = AF_INET;
	address.sin_port = htons(80);
	address.sin_addr = *(struct in_addr *)*hostinfo->h_addr_list;

	/* Create socket */
	sockfd = socket(AF_INET, SOCK_STREAM, 0);

	/* Connect to server */
	if (connect(sockfd, (struct sockaddr *)&address, sizeof(address)) == -1) {
		perror("connect faild!\n");
		exit(1);
	}

	/* Request string */
	len = snprintf(msg, 512,
				  "username=%s&password=%s&type=%s&encoding=%s&popup=%s&mo=%s&mobile=%s"
				  "&message=%s&vldtime=%s&dlvtime=%s", username, password, type, encoding,
				  popup, mo, mobile, message, vldtime, dlvtime);

	/* HTTP request content */
	snprintf(MSGData, 512,
			"POST /send_sms.php HTTP/1.1\r\n"
			"Host: %s\r\n"
			"Content-Length: %d\r\n"
			"Content-Type: application/x-www-form-urlencoded\r\n"
			"Connection: Close\r\n\r\n"
			"%s\r\n", host, len, msg);

	/* Send message */
	send(sockfd, MSGData, strlen(MSGData), 0);

	/* Response message */
	recv(sockfd, buf, 512, 0);

	for (res = strtok(buf, "\n"); strncmp(res, "resp", 4) != 0; res = strtok(NULL, "\n"));
	checkRes = strtok(res, "=");
	checkRes = strtok(NULL, "=");

	if (atoi(checkRes) <= 0) {
		printf("傳送失敗\n");
	} else {
		printf("傳送完成\n");
	}

	close(sockfd);
	return 0;
}

C/C++, 程式筆記 , , ,

C 語言中 printf 的問題(續)

九月 30th, 2007

前一篇當中提到了 printf 結果異常的問題,在睡前翻了一下手邊借來的「C Primer Plus」,沒想到就有提到這個問題,印象中其他書籍似乎都沒有講到,C Primer 系列果然是好書!

簡單來說就是 C 語言中,compiler 可以選擇先計算函數中的哪個參數,以增加編譯程式的效率,所以前一篇的例子:


printf("%d, %d", age, age++);

compiler 很可能會先算第二個參數,先改變了 num 數值,這樣就造成結果不如預期了。

在「C Primer Plus 5/e 中文精華版」第五章有寫道,遵循以下原則可以避免這些問題:

  1. 請勿在函數當中,對使用不止一次的參數使用遞增或遞減運算子。
  2. 請勿在運算式當中,對使用不止一次的變數使用遞增或遞減運算子。

第一點就是上面所說的例子,第二點的例子如下:


n = 3;
y = n++ + n++;

在 C 標準中並沒有定義這行程式會如何執行,是哪一個先加 1 再運算,還是都先不加,造成了含糊不清的結果,應當避免這種寫法。

C/C++, 程式筆記 ,

C 語言中 printf 的問題

九月 30th, 2007

今天有個學妹問我一個 C 程式的問題:下面程式的結果為何?


#include <stdio.h>
int main(void)
{
    int age = 20;
    printf("You are now %d, and will be %d in one year", age, age++);
    return 0 ;
}

自認觀念還不錯的我直接就回答「20, 20」。但沒想到實際跑的答案竟然是「21, 20」,這真是出乎意料的結果啊!

馬上另外測試了其他有 printf 函式的語言,如 Java、PHP,結果也都是正確的「20, 20」,所以不知道是 C printf 的 bug 還是什麼原因,希望有人能解答。

請看:C 語言中 printf 的問題(續)

C/C++, 程式筆記 , ,

OpenGL-海龜作圖法

一月 16th, 2007

海龜作圖法(Turtle Graphics),意思是模仿海龜移動的方式,只能前進及左右轉,而將海龜的尾巴當作畫筆,可以放下及抬起。
本範例為二維空間,使用 OpenGL 搭配 C++ 實做。

程式功能介紹:
1、由 turtle.txt 檔案讀入作圖指令。
2、INIT - 設定海龜初始位置。(x 軸, y 軸, 龜頭角度)
3、PEN - 設定尾巴狀態。(0 抬起 / 1放下)
4、FW - 海龜向前移動。(移動長度)
5、RIGHT - 海龜右轉角度。(角度)
6、LEFT - 海龜左轉角度。(角度)


#include <iostream>
#include <fstream>
#include <cstring>
#include <cmath>
#include <GL/glut.h>
using namespace std;

const GLfloat PI = 3.141593;

class Turtle {
private:
    bool penStatus, a;
    GLfloat x1, y1, x2, y2; //座標
    GLfloat cAngle; //角度
public:
    Turtle() //constractor
    {
        penStatus = 0;
        x1 = y1 = x2 = y2 = 0.0;
        cAngle = 0.0;
        a = 0;
    }

    /* 設定海龜位置 */
    void InitPoint(GLfloat x, GLfloat y, GLfloat angle)
    {
        x1 = x; y1 = y; cAngle = angle; a = 1;
        if (penStatus) //如果 pen down 應該畫出一點
        {
            glBegin(GL_POINTS);
                glVertex2f(x, y);
            glEnd();
        }
    }
    /* 海龜向前移動 */
    void forward(GLfloat L)
    {
        x2 = x1 + L * cos(cAngle*PI/180);
        y2 = y1 + L * sin(cAngle*PI/180);

        if (penStatus)
        {
            glBegin(GL_LINES);
                glVertex2f(x1, y1);
                glVertex2f(x2, y2);
            glEnd();
        }

        x1 = x2; y1 = y2;
    }
    /* 海龜右轉角度 */
    void right(GLfloat angle)
    {
        cAngle = (a) ? cAngle - angle : angle;
        a = 1;
    }
    /* 海龜左轉角度 */
    void left(GLfloat angle)
    {
        cAngle = (a) ? cAngle + angle : angle;
        a = 1;
    }
    /* 設定畫筆狀態(0 up/1 down) */
    void setPen(bool value)
    {
        penStatus = value;
		if (value) //pen down 畫出一點
		{
			glBegin(GL_POINTS);
				glVertex2f(x1, y1);
			glEnd();
		}
    }

};

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT);  /*clear the window */

    char cmd[10];
    float x, y, angle;
    bool p;
    ifstream fp("turtle.txt");
    Turtle t;

    while (!fp.eof())
    {
        fp >> cmd;
        if (!strcmp(cmd, "INIT")) {
            fp >> x >> y >> angle;
            t.InitPoint(x, y, angle);
        } else if (!strcmp(cmd, "FW")) {
            fp >> x;
            t.forward(x);
        } else if (!strcmp(cmd, "RIGHT")) {
            fp >> x;
            t.right(x);
        } else if (!strcmp(cmd, "LEFT")) {
            fp >> x;
            t.left(x);
        } else if (!strcmp(cmd, "PEN")) {
            fp >> p;
            t.setPen(p);
        }
    }

    glFlush(); /* clear buffers */
}

int main(int argc, char** argv)
{

/* Standard GLUT initialization */
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); /* default, not needed */
    glutInitWindowSize(500, 500); /* 500 x 500 pixel window */
    glutInitWindowPosition(0, 0); /* place window top left on display */
    glutCreateWindow("Turtle Graphics"); /* window title */
    glutDisplayFunc(display); /* display callback invoked when window opened */

/* attributes */
    glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
    glColor3f(1.0, 0.0, 0.0); /* draw in red */
/* set up viewing */
/* 500 x 500 window with origin lower left */
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0, 500.0, 0.0, 500.0);
    glMatrixMode(GL_MODELVIEW);

    glutMainLoop(); /* enter event loop */

    return 0;
}

turtle.txt

C/C++, 程式筆記 ,