본문 바로가기
1.A. High Level Computing/SW Language Specifics

[토막글] C언어 연산자 설명 & 예시 ( /, +=, ++, () ? : , ...)

by Never Settle Down 2023. 3. 14.
반응형

나에게는 CB라는 친구가 있다.

쿨롱 베리어랑 서킷 브레이커가 자꾸 떠올라서

ChB라고 이니셜을 지어주려니 Chubby가 떠오른다.

 

뚱뚱한 (chubby) 애는 아닌데... 자네는 쿨롱 베리어야 이제부터.

 

쿨롱 장벽:

쿨롱 장벽(Coulomb barrier)은 두 원자핵이 핵융합을 일으킬 정도로 가까워지기 위해 극복해야 할 정전기력을 의미한다

 

ㅋㅋ

 

 

 

방통대 소공인지 컴공인지 다닌다고 한다.

(나쁘지 않은 대학 졸업하고도 (나, 쿨롱베리어 2 케이스만 봐도) 원격대학 공대 다니는 사람이 부쩍 느는 것 같다)

 

C언어를 basically 처음 접한다고 해서

연산자 관련해서 팁을 좀 남기려 한다.

 

브금은... 뭐로하지.

 

 

 

Aurora - I Went Too Far

TfMI, 투 뻑킹 머치 인포메이션한 내 성격상

너무 깊게 들어가거나 딴 길로 샐 수 있어서 골랐다.

 

 

I went too far and kissed the ground beneath your feet
Waiting for your love, waiting for our eyes to meet

 

 

씨언어 잘 해봐 재밌어

적어도 나는 재밌어 ㅋㅋ

나중에 아두이노 몇 개 줄까

2023.01.31 - [Engineering Log/Micro Controller Unit] - [MCU] T0. 아두이노 개론.

 

[MCU] T0. 아두이노 개론.

아두이노 How to (h2) 시리즈는 전자과를 졸업하고 전자과를 또 다니는 주인장 NSD로서 임베디드 관련 논문을 쓰고나서 MCU에 관심이 생긴사람, 10년을 함께한 기계공학 석사생 Marius를 위해 쓰는 글

thewanderer.tistory.com

내 졸업대학 친구랑 종교 친구 보라고 글 쓰고 있는데

여기도 C를 쓰거든.

 

 

 

 

...

이거봐 벌써 딴 길로 새고 있다.

 

 

 

 

 

목차

1. 해당 예시 풀이

2. 연산자 설명

   - [ +, - ]

   - [ * ]

   - [ / , % ]

   - [  +=  ,  -=  ,  *=  ,  /=  , %=  ]

   - [ ++ , -- ]

   - [  () ? :   ]

 

3. 연산자 예시

    A. 카이자르 암/복호화기

    B. 아두이노 IR (적외선 리모컨) 사용하기 코드

 

 

 

 

1. 해당 예시 풀이

 

방통대 컴공 C 교재의 [강제 형변환의 예] 풀이입니다.

오타가 있다. 감안해주세요.

소스코드 보기: (오타 수정함)

 

더보기
#include <stdio.h>

int main(int argc, const char * argv[]) {

    int a, b, c;
    a = 10; b = 20; c = 30;
    printf("a + b * c = %d \n", a + b * c);
    printf("a = b += 2 * c -> a = %d \n", a = b += 2 * c);
    printf("a = (b > c) ? b : c -> a = %d \n", a = (b > c) ? b : c);
    printf("a / b * c = %d \n", a / b * c);
    printf("a *= b = c + 5 -> a = %d \n", a *= b = c + 5);
    
    return 0;
}

 

결과 화면

 

첫째.

저걸 쓴 사람은 무슨 생각으로 저걸 저렇게 썼을까??

가독성도 심각하게 떨어지고, 컴파일하면 풀어쓰든 줄여쓰든 똑같은 엑세큐터블 파일이 나오는데.

딱밤 맞을만 하다고 봄.

 

 

둘째.

저게 왜 강제형변환이야?

 

 

셋째.

한 줄씩, 풀어서 같은 코드를 만들어 볼게.

 

더보기

 

여기는 쉽지?

 

[ 곱셈 / 나눗셈 먼저하고, 덧셈한 값] 을 %d 위치에 넣어서 프린트해라.

 

이런 코드 형태는 많이 씁니다.

굳이 temp1이라는 변수를 하나 더 만들어서

메모리를 점유할 필요는 없으니깐.

 

나중에 또 쓸일 있다면 굳이 매번 연산할 필요 없이

기억해뒀다가 불러서 쓸 수는 있겠다만.

 

 

Next.

실제로 오리지널 코드를 실행하게 되면,

CPU 안에선 Register라는 작은 임시저장용 공간 (엄청 빠른 메모리)에 저장하게 되는데,

이걸 일반 메모리에 저장해 임마! 하고 지정해준게 temp1 ~ temp3야.

 

어렵게 말해서 그렇지,

쉽게 말하자면 둘이 (Original이랑 deciphered) 똑같은 코드라구.

 

결과 똑같쥬?

 

오리지널 라인 밑에,

    a = 10;
    b = 20;
    c = 30;

를 넣어준 이유는,

두 번째 printf의 오리지널 코드를 실행하고 나면

a, b의 값이 바뀌기 때문이야.

 

 

a = b += 2 * c

{ [2 곱하기 c 한 값을] b의 기존값과 더하고, 그걸 b에 넣어라.} 그걸 a에 넣어라. 그리고 새로운 a값을 %d의 위치에 넣어라.

 

더럽지.

실무에서 저렇게 쓰면 뒤통수 맞을듯.

다른건 모르겠는데 a = 새로운값. 이걸 printf 안에 넣는다고?

전혀 intuitive하지 않아.

 

 

나는 저게 가능한 줄도 몰랐어.

어차피 저렇게 printf안에 (a=뭐시기) 를 쓰나, 풀어서 쓰나, 결과물 (컴파일 결과물)은 똑같아.

 

 

next.

참 책 쓴사람 대 충 썼다.

printf("a = (b > c) ? b : c -> a = %d \n", a = (b > c) ? b : c);

b가 c보다 크다면 b값을 a에, 아니라면 c값을 a에 넣어라. 그리고 a의 값을 %d 위치에 넣어라.

 

 

 

내가 저자였으면 이렇게 예시를 보여줬을텐데.

만약에 (나중에 나올) 포인터를 쓴다면 대충 이렇게,

 

저게 뭐냐면.

 

메신저에서 얘기했던 것처럼

삼항 연상자 라는 것인데.

뭣인지 궁금하면

아래 연산자 설명을 보세요.

 

ㅋㅋ.

 

 

 

next.

이 라인은 해석만 넣고 제끼자.

a / b * c

a를 b로 나눈 몫을 c와 곱해라.

 

자세한건 아래 연산자 설명 보세요.

 

 

next.

+= -= *= /= 등등 자꾸 나오는데

그거 빼면 같은 코드야.

 

a *= b = c + 5

[c + 5]를 b에 넣어라. 그리고 a와 b를 곱해서 a에 넣어라. 그걸 %d에 띄워라.

 

 

역시, 이전 코드처럼

a 에 뭔 값을 넣는 코드를 저렇게 넣어주면

책임아저씨가 성큼성큼 달려와서

뒤통수를 탁! 하고 칠 것 같은 코드.

 

 

 

 

 

 

 

 

 

2. 연산자 설명

학교 교수님이 잘 설명해주시겠지만

다시 떠들어보자.

 

 

[ +, - ]

 

더보기

그냥 일반 숫자 덧뺄셈이랑 똑같다.

 

 

[ * ]

 

더보기

그냥 일반 숫자 곱셈이랑 똑같다.

 

 

[  /  , %  ]

 

더보기

 

 

 

 

그럼, 기본연산자 뒤에 =가 붙은 녀석들은요?

[  +=  ,  -=  ,  *=  ,  /=  , %=  ]

 

더보기

변수 += 피연산자

변수 = 변수 + 피연산자

int var = 0;

// 지금 시점 var 값 = 0

var += 3;

// 지금 시점 var 값 = 3

var = var + 3;

// 지금 시점 var 값 = 6

 

가릿?

 

덧/뺄/곱/나

다 동일합네다.

 

곱는 은 빼먹었다.

쁠는, 마는, 몫는, 나머지는 만 썼는데, 곱는 은 저스트 이메진 오케이?

 

 

가릿?

노?

 

워낙 기본적이고 자주쓰는 문법이라.

알아둬야할거시여.

 

영어학전공자로서 나의 의견을 써보자면,

 

프로그래밍언어는 일반 언어랑 상당히 비슷해서

- 자주 접하고 사용하면 fluency가 올라감 (능숙해짐)

- 듣기/읽기와 말하기/쓰기의 fluency는 다를 수 있음. 많이 읽는다고 능숙하게 쓸 수 있는건 아님.

 

 

 

이 중에

- 변수 += 1

- 변수 -= 1

는 워낙 자주 쓴느거라 따로 이름도 있다?

 

[ ++ , -- ]

 

더보기

for문을 접해봤으면 봤을 것 같다.

 

쁠쁠만 올릴게, 나머지 마마는 똑같다. 

둘이 1을 더하느냐 빼느냐 뺴고는 똑같거덩.

 

 

a = a + 1;

a += 1;

a++;

 

셋이 같은 표현이야.

 

a++, 많이 짧아지쥬?

 

++은 글자 2개로 바로 표현할 수 있다는 점 외에도

이 것만이 가진 아주 큰 강점이 있어.

 

 

바로, [ 어디에 오느냐에 따라 연산 순서가 바뀐다는 점]이야.

 

 

뭔말이냐고?

 

 보이세요?

차이점이?

 

 

- 변수 뒤에 ++이 올 경우:

   해당 line을 ++없이 실행하고, 변수 += 1를 수행한다.

 

- 변수 앞에 ++이 올 경우:

   변수 += 1를 수행하고나서, 해당 line을 ++없이(이미 했으니까) 실행한다,

 

 

옥희?

 

 

노?

 

 

ㅠㅠ

 

 

삼항연산자는 뭐시여.

 

[  () ? :   ]

 

더보기

변수 = (조건) ? 참일때값 : 거짓일때값;

 

형태로 쓰고,

참일때 값, 거짓일때 값

둘 중 하나를 반환 (return)한다고 생각하면 되.

 

 

앞서 얘기했듯이

if(조건){

   변수 = 참일때값;

} else {

   변수 = 거짓일때값;

}

랑 같은거야.

 

 

 

이걸 왜 쓰느냐.

- 코드를 짧게 쓰고 싶을때 (특히 if하고 {}로 들여쓰기가 들어가면 지저분해지잖아)

- 다른 함수 안에 넣고 싶을때.

 

보통 2번때문에 쓰는 경우가 많아.

 

 

 

 

bool you_want_even_number = true;

printf("%d", (you_want_even_number) ? 2 : 1);

 

이 코드를 보자.

 

불 값이 참 (트루) 이므로

printf를 실행하기 전에

(you_want_even_number) ? 2 : 1

코드를 먼저 실행한다.

 

그럼 2라는 값이 나오겠지?

그걸 프린트 에프에 넣어주는 거야.

 

printf("%d", 2);

 

이렇게 되잖아.

 

 

이걸 if문으로 구현하려고 한다면...

printf("%d", if(조건문){...} else{...});

이렇게 쓸 수가 없거든.

 

지금이야 프린트 에프 하나만 쓰기때문에

이프문 안에 프린트를 넣으면 되지만

그게 불가능한 경우도 있어.

 

그럴때 쓰는것이여.

 

 

 

당근 이중 삼항연산자도 된다.

 

 드럽지?

 

잘 안 써.

가능은 한데, 안 써.

 

 

 

 

궁금한거 있으면

물어보세요.

 

 

구글에게.

ㅋㅋ

 

 

 

지금까지 떠든 내용은

- 파이썬

- R

- 자바

등등 다른 언어에서도 많이 쓰는 문법이거든.

 

꼭. 익숙해지길.

 

 

지금까지 떠들면서 쓴 코드

 

더보기
//
//  main.c
//  chb_examples
//
//  Created by NeverSettleDown on 2023/03/14.
//

#include <stdio.h>
#include<stdbool.h>

int main(int argc, const char * argv[]) {

    int a, b, c;
    a = 10; b = 20; c = 30;
    
    
    /*
    //Original Line
    printf("a + b * c = %d \n", a + b * c);
    
    //Deciphered Line
    int temp1 = a + b * c;
    //temp 1 = 10 + 20 * 30;
    printf("a + b * c = %d \n", temp1);
    */
    
    
    
    /*
    //Original Line
    printf("a = b += 2 * c -> a = %d \n", a = b += 2 * c);
    
    a = 10;
    b = 20;
    c = 30;
    
    //Deciphered Line
    int temp2 = 2 * c;
    
    int temp3 = b + temp2;
    b = temp3;
    
    a = b;
    printf("a = b += 2 * c -> a = %d \n", a);
    */
    
    
    
    
    /*
    //Original Line
    printf("a = (b > c) ? b : c -> a = %d \n", a = (b > c) ? b : c);
    
    a = 80;
    //Deciphered Line
    if(b > c)   { a = b; }
    else        { a = c; }
    printf("a = (b > c) ? b : c -> a = %d \n\n", a);
    
    
    int tina = 80, queeny = 50;
    printf("Highest Point is %d \n", (tina > queeny) ? tina : queeny);
    printf("The Winnder is ");
    printf((tina > queeny) ? "Tina" : "Queeny");
    
    printf("\n\n");
    
    const char* str_tina = "Porpentina Goldstein";
    const char* str_queeny = "Queeny Goldstein";
    printf("My Favourite Character in Fantastic Beasts is: ");
    printf("%s \n", (tina > queeny) ? str_tina : str_queeny);
    */
    
    
    /*
    
    //Original Line
    printf("a / b * c = %d \n", a / b * c);
    
    //Deciphered Line
    int temp4 = a / b * c;
    */
    
    
    
    /*
     
     a = 80;
     b = 80;
     c = 30;
    //Original Line
    printf("a *= b = c + 5 -> a = %d \n", a *= b = c + 5);
    
    a = 80;
    b = 80;
    c = 30;
    //Deciphered Line
    int temp5 = c + 5;
    b = temp5;
    int temp6 = a * b;
    a = temp6;
    printf("a *= b = c + 5 -> a = %d \n", a);
    
    
    //*/
    
    
    
    /*
    int integer1 = 11;
    int integer2 = 2;
    
    double double1 = 11.0;
    double double2 = 2.0;
    
    printf("11 / 2 = %d \n", integer1 / integer2);
    printf("11 %% 2 = %d \n", integer1 % integer2);
    printf("11.0 ÷ 2.0 = %f \n", double1 / double2);
    */
    
    
    /*
    int var;
    
    var = 2;
    var += 1;
    printf("var was 2. var += 1 -> var = %d \n\n", var);
    
    var = 2;
    var -= 1;
    printf("var was 2. var -= 3 -> var = %d \n\n", var);
    
    var = 5;
    var /= 3;
    printf("var was 5. var /= 3 -> var = %d \n\n", var);
        
    var = 5;
    var %= 3;
    printf("var was 5. var %%= 3 -> var = %d \n\n", var);
    
    */
    
    
    
    
    
    /*
    
    int var = 5;
    printf("before Var++: %d \n", var);
    printf("doing  Var++: %d \n", var++);
    printf("after  Var++: %d \n", var);
    
    printf("\n");
    
    var = 5;
    printf("before ++Var: %d \n", var);
    printf("doing  ++Var: %d \n", ++var);
    printf("after  ++Var: %d \n", var);
    
     */
    
    
    /*
     
    bool you_Want_Odd_Number = false;
    bool you_Want_Prime_Number = false;
    
    printf("%d", (you_Want_Odd_Number) ?
                        (you_Want_Prime_Number) ? 1 : 9//you_Want_Odd_Number = true
                    :
                        (you_Want_Prime_Number) ? 2 : 4//you_Want_Odd_Number = false
           );
    
    
    */
    
    printf("\n\n\n\n");
    return 0;
}

 

 

 

 

 

C 연산자예제

예제를 보자.

 

 

A. 시져 암복호화기

이번에 "암호학 개론" 듣는데

여기서 제출한 내 과제.

 

카이사르 (시져) 복호화기 이다.

 

카이사르 암호화 기법에 대해 간단히 설명하자면.

 

더보기

평문 (암호화 전 문장)과 Key (정수이다)를 가지고 간단히 치환하는 암호화 기법.

 

글자를 Key 번째 다음에 오는 문자로 치환한다.

 

 

예로,

Key = 1일때

' ABC '

라는 문장을 암호화하면

' BCD '라는 암호문이 나온다.

 

 

Key는 1부터 25 (영어 알파벳 기준 26개 - 1)까지이고.

암호화 수준은 처참하다.

띄어쓰기도 유지하고, key 범위도 제한적이기 때문에.

 

당시에 이 방법을 썼던건

- 간단하고

- 문맹이 많았기 때문에

쓸만했다.

 

 

 

Key = 3일때 예제

 

 간단하다.

그치?

 

... 아냐?

아님 말구 뭐...

 

 

소스코드:

 

더보기
//
//  main.c
//  Caesar Decipher
//
//  Created by NSD on 2023/03/10.
//

#include <stdio.h>
#define cipheredStrLength 13
#define numOfAlphabet 26

int main(int argc, const char * argv[])
{
    const char str[cipheredStrLength + 1] = "TPHN ID QGTPZ\0";
    char decipheredStr[numOfAlphabet][cipheredStrLength + 1];
    
    printf("CAESAR DECIPHER\nEncrypted string: ");
    printf("%s\n", str);

    for(int key = 0; key < numOfAlphabet; key++)
    {
        for(int i = 0; i < cipheredStrLength; i++)
        {
            if(str[i] == ' ')
            {
                decipheredStr[key][i] = ' ';
                continue;
            }
            decipheredStr[key][i] = str[i] + key; //shift to k then save
            decipheredStr[key][i] -= (decipheredStr[key][i] > 'Z') ? numOfAlphabet : 0;
            //if shifted char overshoots, cycle it back.
            
            //ascii: A = 65, a = 97, delta = 32
            decipheredStr[key][i] += 32; //Capital char to small char
        }
        //adding End of String (null) at the end.
        decipheredStr[key][cipheredStrLength] = '\0';
    }
    
    for(int index = 1; index < numOfAlphabet; index++)
    {
        // printing each cases of shift "k"
        printf("k = %d: %s\n", index, decipheredStr[index]);
    }
    
    return 0;
}

결과 화면은 전수조사 해서 육안으로 검사하는 것이다.

 

Key = 11일 때

Easy to Break (뚫기 쉽다)

가 정답.

 

...

너무 코드가 어려울려나??

ㅜㅜ

 

함 읽어봐...

 

 

 

 

 

B. 아두이노 IR 송신기 코드

 

내가 친구샛기들 보라고 가끔 코드 올리고 있는데

안봐서 그렇지

연산자 예시로 쓰기 좋은 것 같아서 올린다.

 

갑자기 황석영 야생초편지를 전산버전으로 쓰고 있는 기분이 든다.

 

2023.03.21 - [Engineering Log/Micro Controller Unit] - [MCU] P3. 적외선 리모컨 사용하기 (수신, 발신)

 

[MCU] P3. 적외선 리모컨 사용하기 (수신, 발신)

그렇게 아두이노 글 올려달라던 친구 몇 놈들은 아두이노 관련 글을 1도 안 올리는데 연락이 없다. 안 하고 안 보는 것임. ㅋㅋ 피드백 달라고 몇 명에게나 부탁했으나 정작 나에게 블로그 포스

thewanderer.tistory.com

 

다른건 사실 볼거 없고

아래 적외선 송신기 코드를 보자.

 

#include <Arduino.h>
#include <IRremote.hpp>
#define DISABLE_CODE_FOR_RECEIVER
#define IR_SEND_PIN 3

const int commands[] = {
  0xB, 7, 0xD, 8, 0x5D, 2, 0x5E
};

void setup() 
{
    Serial.begin(115200);

    Serial.println(IR_SEND_PIN);

    IrSender.begin(IR_SEND_PIN);
}

void loop() 
{
  static int i = 0;
  IrSender.sendNEC(0xFC, commands[i], 0);
  Serial.println(i);
  (++i == 7) ? i = 0 : i = i;
  
  delay(500);
}

 

일반 PC용 C랑은 소프트웨어 아키텍쳐나 구동 특성이 달라서 그렇지.

Void Loop 내용은 여느 C99랑 다른게 없다.

 

엄밀히는 C++로 알고 있는데.

기초과정에선 C99나 C11이나 C++이나

그게 그거여. Same o same o. twa.

 

 

 

간단히 설명해보면;

- 적외선 명령어는 7개가 있다. 위/오른/아래/왼 방향키 + 선택 / 메뉴 / 정지재생

- 이 7개 명령어를 순차적으로 보낼 것이다.

- 한 명령어를 쏘고(IrSender.sendNEC(...)) 0.5초 기다린다. (delay(500))

- 7번째 명령어를 쏘고 나면 첫번째로 돌아간다.

 

 

"배열" 이라는 형태로 명령어를 저장했어.

그게

const int commands[] = {
  0xB, 7, 0xD, 8, 0x5D, 2, 0x5E
};

코드야.

 

const: 변수 값을 바꾸지 않을 것이라고 선언. (리모컨 데이터니까 내가 바꿀 이유가 없지)

commands: 변수명

[] : 동적 배열 할당.

아마 PC에서 C로 만들면 정적배열을 써야될지도 몰라.

const int commands[7] = {...,...,... ...};

이렇게.

 

 

 

void loop()함수는 아두이노에서

무한히 반복하는 함수야.

 

PC C언어에서 while(true) { ... } 로 감쌌다고 생각하면 되.

 

 

 

static int i = 0;

이건 아두이노에서

- void loop() 처음 실행할땐 안에 i 변수를 선언하고,

- loop() 내의 맨 윗 코드로 돌아왔을 때, i를 0으로 초기화하지 말라고

명령하는거여.

 

그냥 그려러니~

 

 

 

그럼.

 

void loop() 
{
  static int i = 0; // 배열 인덱스(index)로 쓸 변수 i 선언
  IrSender.sendNEC(0xFC, commands[i], 0); //리모컨 신호 발사
  Serial.println(i); //무시해도 됨.


  (++i == 7) ? i = 0 : i = i;
  
  delay(500); //0.5초 대기.
}

이정도 주석이면 될 것 같다.

 

 

 

이번에 떠들고 싶은 한 줄.

  (++i == 7) ? i = 0 : i = i;

이 코드가 보입네까??

 

삼항연산자와 ++를 쓴 코드입니다.

같은 코드:

i = i + 1;

if(i == 7) {
   i = 0;
}
else {
   i = i; //쓸데 없는 연산
}

 

i = i 부분은

삼항연산자를 완성하기 위해 넣은거라 불필요한 부분이야.

 

어른주스 (7년산 밸런타인) 까먹으면서

대충 짠거라 그냥 타타닥 친것임.

 

 

 

(++i == 7) ? i = 0 : i = i;

i에 1을 먼저 더해 저장하고, 그 i 값이 7이 되면 i 를 0으로 초기화시키라. 아니면 i 에 i 값을 넣어라.

 

 

7개짜리 배열 데이터를

순서대로 돌아가면서 불러오겠지?

 

이해 됩네까?

안다스탠? 모른다스탠??

 

공학대학 졸업했으니 저정도는 알아들을듯...

 

 

 

 

배열을 배웠으면

왜 7개 데이터가 들어가는 배열에서

인덱스를 0 ~ 6까지만 쓰는지 알 것이고

 

안 배웠으면 나중에 배우고 돌아오면 된다.

n개 데이터를 담은 배열은

인덱스를 0 ~ n-1 까지 쓴다고 기억하면 된다.

 

 

왜그런지 설명하자면 한 주 분량의 강의가 나와버리니까.

돈 냈잖아 학교에서 배워. ㅋㅋ

 

 

 

 

 

 

끝. End of Doc

 

반응형

Comment(s)