Clang
202 subscribers
48 photos
3 videos
8 files
48 links
یه کانال شخصیه برای تمرین C. اگه جایی اشتباه بود خوشحال می‌شم بگین.
https://t.me/ccismywife
Download Telegram
Clang
#include <stdio.h>
int func1(int), echo(int);
int func1(int input)
{
return input;
}
int echo(int number)
{
func1(number) + 1;
}
int main()
{
int echo_five = echo(5);
printf("From main => %d\n", echo_five);
return 0;
}
کد اسمبلی که تولید شده:
  .file  "main.c"
.text
.globl func1
.def func1; .scl 2; .type 32; .endef
.seh_proc func1
func1:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
.seh_endprologue
movl %ecx, 16(%rbp) #اینجا مقدار پارامتر ورودی رو میخونیم
movl 16(%rbp), %eax # همون مقدار رو در ریجستر eax قرار میدیم
popq %rbp
ret
.seh_endproc
.globl echo
.def echo; .scl 2; .type 32; .endef
.seh_proc echo
echo:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movl %ecx, 16(%rbp)
movl 16(%rbp), %eax
movl %eax, %ecx
call func1
nop #توجه کردید؟ هیچ کاری با eax بعد از فراخوانی قبلی نداشتیم
addq $32, %rsp
popq %rbp
ret #پایان تابع فعلی
.seh_endproc
.def __main; .scl 2; .type 32; .endef
.section .rdata,"dr"
.LC0:
.ascii "From main => %d\12\0"
.text
.globl main
.def main; .scl 2; .type 32; .endef
.seh_proc main
main:
pushq %rbp
.seh_pushreg %rbp
movq %rsp, %rbp
.seh_setframe %rbp, 0
subq $48, %rsp
.seh_stackalloc 48
.seh_endprologue
call __main
movl $5, %ecx #آماده سازی آرگومان
call echo
movl %eax, -4(%rbp) #مقدار eax همونیه که تابع func1 میگه :)
movl -4(%rbp), %eax
movl %eax, %edx
leaq .LC0(%rip), %rax
movq %rax, %rcx
call printf
movl $0, %eax
addq $48, %rsp
popq %rbp
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-Builds project) 13.2.0"
.def printf; .scl 2; .type 32; .endef
🤯2
به کد زیر توجه کنید:
#include <stdio.h>
int main(void) {
int a, b;
//&a => 3AA59FFC8C
//&b + 1 => 3AA59FFC8C
int *p = &a;
int *q = &b + 1;
printf("%p %p %d\n", (void *)p, (void *)q, p == q);
return 0;
}

خروجی رو توی حالت معمولی در gcc چی میشه؟ توی حالت O1(بهینه سازی) چی؟ آدرس هارو هم که دارید... #چالش
https://t.me/ccismywife/15044
🤔5
Forwarded from CBE ARCHIVE
This media is not supported in your browser
VIEW IN TELEGRAM
انجمن CS12 چطور کار میکنه؟ 🧐

توی این ویدیو بصورت مختصر مفید با فلسفه کامیونیتی ما آشنا تر میشید


CBE Archive | CS12 Society
Please open Telegram to view this post
VIEW IN TELEGRAM
1🔥1
اگه دارین یک زبان برنامه نویسی خاص یاد میگیرین، خواهش میکنم تحت هیچ شرایطی ازش فاصله نگیرید و از این شاخه به اون شاخه نپرید و فکر نکنید میشه همزمان توی دو تا زبان دیپ شد!
توی این تله نیفتید و تمرکز کنید رو یک زبان، وقتی از نظر خودتون به اندازه کافی یادش گرفتید، اونوقت برین سراغ زبانی که دوست دارید یاد بگیرید....
مثلاً به اندازه کافی c رو یاد گرفتید(از نظر خودتون البته)، بعدش برین سراغ cpp یا java...
هم خدا و خرما رو همزمان نخواید، به نوبت بخواید😂 منظورم اینه...
وقتی فاصله بگیرید، برگشت سخت میشه
#تجربه
👏62
تا حالا برات سوال شده چرا باید
\?
هم جزئی از Escape Sequence ها باشه؟ مگه نمیتونیم مستقیم از علامت سوال استفاده کنیم؟
خب، بله میتونیم ولی کد زیرو نگاه:(با فرض اینکه قابلیت trigraph کامپایلر روشن باشه!)
#include <stdio.h>
int main()
{
printf("???(");
return 0;
}

خروجی این کد چیزی نیست که انتظار داریم:
?[

اون قدیم ندیما بعضی از کیبرد ها ] و [ و... رو نداشتن و طراح های زبان به اونا هم فکر کردن و راه حال جایگزین براشون گذاشتن، یعنی هر جا نیاز به ] باشه میشه از )?? استفاده کرد.
ولی بدیش اینه که حتی توی رشته ها هم توسط پیش پردازنده تفسیر میشه و برای حلش باید از
\?
استفاده کنیم... همین
هر چند الا دیگه این قابلیت به صورت پیشفرض خاموشه ولی دونستنش بد نی...
#نکته
1👏1
منظور از از object file همون فایل های باینری کامپایل شده اس...
اگه متن دوم که درباره library ها حرف زده براتون عجیبه باید بدونید که فایل های .lib شامل مجموعه ای از module ها(obj files) هستش... پس به فرمت .lib گیر ندید بگید کتابخانه های کامپایل شده که فرمتشون .obj نی .lib هستش... .lib یک کالکشن از .obj هاس...
#نکته
👏3
اگه این قانون توی ساخت توکن توی فرایند کامپایل در زبان c درک کنیم، عبارتی که در ادامه میاد رو مثل یک کامپایلر میخونیم.
قانون:
(فرض کنید دارید کاراکتر به کاراکتر سورس رو میخونید، شما هر کاراکتری که میخونید رو به قبلی اضافه میکنید، ولی فقط به شرطی که که whitespace نباشه؛ حالا اگه متوجه شدید که توکنی که قبلا درست بوده با خطا رو به رو شده، آخرین کاراکتر رو نادیده میگیریپ و میرین سراغ استخراج توکن بعدی و به همین ترتیب.)
مثلاً کد زیر:
a+++7+++b;

اول a رو خوندیم، حالا+ رو خوندم، a+ نامعتبره، پس فعلا فقط a رو دارم و میرم سراغ استخراج توکن بعدی، از همین جایی که تموم کردم، یعنی اولین +
حالا که + رو داریم، کاراکتر بعدی رو میخونیم و + رو داریم و نتیجه شده ++ که معتبره توی c، حالا کاراکتر بعدی شد + و نتیجه توکن فعلی نامعتبر میشه +++، پس میریم سراغ توکن جدید از اینجا، ولی فعلاً موارد زیر رو داریم:
a
++
خب حالا 7 رو داریم و کاراکتر قبلی هم + بود و +7 رو داریم که اعتبار نداره پس حالا دوباره از 7 شروع به خوندن میکنیم و فعلا یک علامت جمع داریم.
کاراکتر بعدی هم + هست و 7+ هم معتبر نی.
پس فعلاً اینارو داریم:
a. ++. +. 7.
حالا یک + دیگه داریم و نتیجه شده ++و معتبره ولی اگه یکی دیگه بخونیم میشه +++ که معتبر نی و موارد زیر رو داریم
a. ++. +. 7. ++.
بله، این باعث مشکل میشه! 7++ که نمیشه چون 7 که l value نی!
پس این انتظاری که داشتید نشد:
a++ + 7 + ++b;

بعله... اینم از این...
#نکته مولایی
🔥3
برای مقایسه دو تا اشاره گر که مطمئن هستید توسط مقایسه معمولی باعث UB میشن، پیشنهاد میشه از uintptr_t استفاده کنید. یعنی نوع اشاره رو تبدیل کنید به uintptr_t.
اینطوری حتی اگه مثال زیر رو با O1 کامپایل کنید و مطمئن باشید که آدرس ها برابرن، ولی مقایسه ای صورت نمی‌گیره، این مشکل حل میشه و کامپایلر موظفه که معادل های uintptr_t ها رو مقایسه کنه.
https://t.me/clangpv/233
#نکته
(البته توی بهینه سازیی هایی مثل O3 یا بالا تر، آدرس ها اصلاً برابرنیستن توی کدی که نوشتیم...)
Clang
اگه این قانون توی ساخت توکن توی فرایند کامپایل در زبان c درک کنیم، عبارتی که در ادامه میاد رو مثل یک کامپایلر میخونیم. قانون: (فرض کنید دارید کاراکتر به کاراکتر سورس رو میخونید، شما هر کاراکتری که میخونید رو به قبلی اضافه میکنید، ولی فقط به شرطی که که whitespace…
دوستان من همچین مباحثی رو به دلیل علاقه ام و جالب بودن برای خودم منتشر میکنم، وگرنه شما نیازی نی خیلی دیپ شین تو این قضیه ها... این مطلب که لینکش در ادامه اومده حرفاش حقه. اگه صرفاً دنبال کار هستید یا از این مباحث لذت نمیبرید نیازی هم نیست درباره همچین چیز هایی مطالعه کنید...
https://t.me/ccismywife/15840
Forwarded from CBE ARCHIVE
درود مجدد رفقای خوبم 🌸

خبر جدید این هست که تیم فنی ما در حال گسترشه و در این مسیر، دنبال یک توسعه‌دهنده‌ی فرانت‌اند مشتاق و توانمند هستیم که بخواد بخشی از یک تیم ما باشه.

اگه به دنبال فرصتی برای کار تیمی و مشارکت در پروژه‌ای هستی که خروجی‌ش می‌تونه رزومه‌ی قوی ای برات باشه، ما ی فضای واقعی برای رشد و ساختن چیزی معنادار داریم.

در طول همکاری کد‌هاتون ریویو می‌شن و با گرفتن بازخورد ایراداتون هم برطرف میشه، به عنوان عضوی از تیم، توی تصمیم‌ها و پیاده‌سازی‌ها مشارکت می‌کنید و تجربه‌ی کار تیمی واقعی کسب می‌کنی


البته ما صرفاً دنبال یه «نیروی کمکی» نیستیم؛ دنبال کسی هستیم که این فرصت رو درک کنه و بخواد توی تیم ما رشد کنه، چون ما هم قراره کنار هم یاد بگیریم و پیش بریم.

اگه حس می‌کنی این مسیر میتونه مسیر تو باشه، این فرم رو پر کن تا باهم در ارتباط باشیم.

https://forms.gle/iRw4mPMtgmq5E5Bt8
لینک فرم 👆

❣️ CBE Archive | CS12 Society
Please open Telegram to view this post
VIEW IN TELEGRAM
3
یک نکته درباره استفاده از رشته های پویا و تابع strcat:
زمانی که از strcat و malloc با هم استفاده میکنید، حواستون باشه که حافظه پویا رو با مقدار 0 پر کنید وگرنه به مشکل بر میخورید! چون malloc تضمین نمیکنه که حافظه ای که بهتون میده همه اش 0 باشه و strcat هم که قراره به انتهای رشته چیزی اضافه کنه، و اول سعی میکنه انتهای رشته مقصد رو پیدا کنه تا بهش اضافه کنه، مثلاً کد زیر ممکنه درست کار نکنه:
    char *ret = malloc(len, sizeof(char));
ret[len - 1] = '\0';
strcat(ret, s);
strcat(ret, str);

#هشدار
به جاش میتونید از calloc استفاده کنید، درسته کنده ولی خو همش صفره...
👍6
Forwarded from CBE ARCHIVE
🌐 لایسنس AGPL چیه؟

لایسنس AGPL یا همون GNU Affero General Public License رو میشه یه نسخه‌ی ارتقا یافته از GPL دونست که...


🔗 Read more on:
📱 Linkedin (در لینکدین بخوانید)

Virgool (در ویرگول بخوانید)


CBE Archive | CS12 Community
Please open Telegram to view this post
VIEW IN TELEGRAM
خب بردگردیم سر C و با سوالی ساده شروع میکنیم:
#include <stdio.h>

int main(void) {
int i = 5;
printf("%d %d %d\n", i, i++, ++i);
return 0;
}

خروجی چیه؟
اینجا میتونید با دلیل پاسخ بدید...
گاهی نیاز داریم توی C یک رشته رو توی چند خط بنویسیم ولی در نهایت همشون با هم الحاق شن. توی زبان هایی که از operator overloading پشتیبانی میکنن که آب خوردنه؛ کافیه از عملگر + استفاده کنید. ولی توی C دو تا راه دارید:
#include <stdio.h>
int main(){
const char *str = "Hello "
"World";
const char *str2 =
"Hello \
World";
printf("%s\n", str);
printf("%s\n", str2);
return 0;
}

خروجی همونیه که انتظار داریم:
Hello World
Hello World

از روشی که برای str2 استفاده کردیم توی ماکرو ها هم استفاده میشه. کلاً هر زمان توی یک سورس زبان C که انتهای خطش با \ تموم شه، پیش پردازنده باید خط بعدی رو وصل کنه به خط قبلی، طوری که انگار کلش توی یک خط نوشته شده.
#نکته
تفاوت Initialize با assignee کردن
بعضیا متاسفانه مفهوم این دو تا مورد رو یکی میدونن... خیلی خلاصه:
مفهوم Initialize: مقدار دهی اولیه در هنگام تعریف یک object که فقط یک بار قابل انجامه!(در هنگام تعریف دیگه)
مفهوم assignee: مقدار دهی بعد از تعریف. این مورد مقدار قبلی معتبر رو از بین میبره
توی Init کردن ما مقدار قبلی معتبری نداریم که قرار باشه از بین بره... #نکته
عبارات، دستورات
دستورات(Statements) توی زبان های برنامه نویسی در حقیقت کاری که باید انجام بشه رو مشخص میکنن و عبارات(Expressions)، همون کاری هستن که باید انجام بشن.
مثلاً ما میتونیم به کامپایلر بگیم که اصلاً هیچ کاری نکن! مثل کد زیر:
int main(){
;//null statement
}


توی اون بخش شما میتونید یک Break point روی null statement بزارید، ولی این دستور هیچ کار خاصی انجام نمیده.(البته بستگی به دیباگر و سطح بهینه سازی هم داره که Break point کار کنه یا نه)
عبارات در زبان C
به صورت کلی یک عبارت در زبان C، یا باید یک مقداری تولید کنه، یا باید یک اثر جانبی داشته باشه، یا هم باید مقدار تولید کنه و هم اثر جانبی داشته باشه(حتی ممکنه که نه اثر جانبی داشته باشه نه مقداری تولید کنه😅). مثلاً فرض کنید که یک تابع به نام show داریم که یک متن رو روی صفحه مینویسه، نوع برگشتی این تابع هم void هستش، درسته که مقداری تولید نمیکنه، ولی اثر جانبی داره!(روی صفحه نمایش اثر میزاره، یا حتی ممکنه بر اساس پیاده سازی خاصی که داره، یک قسمت خاص از حافظه هم تغییر بده)
انواع عبارت در C
به صورت کلی، از دید سطح بالا، هر عبارت میتونه شامل زیر عبارت باشه. عبارت هایی که شامل زیر عبارت هستن رو compound expressions میخونیم و عبارت هایی که خودشون تنها عبارت موجود هستن رو primary expressions میخونیم.
نمونه Compund:
10 + '\n';
2.0 * sin( 3.14159 * fAngleDegrees/180.0 );

اگه توجه کنید، ما میتونیم از دل عبارت دومی، در مرحله اول دو تا زیر مجموعه به دست بیاریم:
2.0;
sin( 3.14159 * fAngleDegrees/180.0 );

عبارت اولی اینجا دیگه زیر عبارت نداره و خودش تنها عبارت موجوده(2.0) پس این یک نوع primary محسوب میشه! قضیه میتونه پیچیده تر هم باشه، توی خط دوم اسم تابع به خودی خود میتونه یک عبارت باشه، ول وقتی با () بیاد یک عبارت فراخوانی تابع حساب میشه که از نظر منطقی نمیتونیم بگیم که sin() خودش به تنهایی میتونه یک عبارت باشه، چون یک ورودی میخواد! ولی میتونید آرگومان ها رو هم تجزیه کنید...
درک کردن عبارت ها و ساختارشون میتونه خیلی توی درک کد های پیچیده بهتون کمک کنه.... سعی کنید کد هاتون رو تمیز بنویسید و پیچده اش نکنید، مگه اینکه به تحلیل جماعت علاقه داشته باشید...
نه اثر جانبی داره، نه مقدار تولید میکنه، ولی عبارته؟ چطوری خو...؟
(void)1;//اینطوری
i + j;//مقدار تولید میشه، ولی بلافاصله دور ریخته میشه، اثر جانبی هم نداره

اولی: این الاً یک عبارت معتبر حساب میشه که نمیتونیم از مقدارش استفاده کنیم(چون مقدار رو تولید نمیکنه و نادیده میگردش)، نه اثر جانبی داره!
دومی: توی این یکی یک مقداری تولید میشه، ولی خو استفاده نمیشه
#نکته
l-value & r-value
به صورت کلی، توی زبان C دو تا دسته بندی برای عبارت هایی وجود داره که یک مقداری تولید میکنن، یکی l-value و یکی هم r-value...
l-value
یکی از توضیحاتی که درباره l-value خوندم که برای شروع دید خوبی به آدم میده ولی کاملاً درست نیست، اینه که l از left میاد و این یعنی عبارت هایی که از این دسته هستند میتونن سمت چپ عملگر تساوی قرار بگیرن. ولی توضیح دقیق تر اینه: عبارت l-vlaue به عبارتی میگن که توسط اون بتونیم مقداری که توی خودش داره رو حداقل یک بار بتونیم تغییر بدیم(یا تعیین کنیم).
شاید جایی خونده باشید که عبارت l-value به عبارتی میگن که یک object رو به همراه آدرسش برمیگردونه؛ دلیل اینکه از این توضیح استفاده نکردم اینه که حالت هایی وجود داره که یک عبارت ممکنه به جای دسترسی به یک آدرس در حافظه برای تغییر مقدار، از روش دیگه ای استفاده کنه.
پس بیاید یک جور دیگه شرحش بدیم:
یک عبارت l-value همیشه میتونه یک object address برگردونه اگر و فقط اگر با یک bit-field یا register storage class طرف نباشیم! چون bit-field ها و متغییر هایی که از کلاس حافظه register استفاده میکنن شاید قابل تغییر باشن، ولی از نظر استاندارد نمیشه آدرسشون رو به دست آورد! اگه بیشتر دقت کنید، توضیح اول و دوم همدیگرو تکمیل میکنن!
عبارت l-value غیر قابل تغییر
درسته، ما یک سری عبارت داریم که درسته l-value هستن، ولی قابل تغییر یا به اصطلاح assignee کردن هم نیستن، ولی میشه اونارو Initialize کرد(بیشتر)! مثلاً زمانی که با const ثابتی تعریف میکنید، نمیتونید مقدارش رو تغییر بدید حتی با اینکه یک نوع object حساب میشه و توی حافظه میتونه آدرس داشته باشه! همچنین زمانی که یک آرایه هم تعریف میکنید نمیتونید بعداً دوباره مقدار دهیش کنید!
#include <stdio.h>
int main()
{
int arr[3] = {0,0,0};//Initialize
const int b = 4;//Initialize
arr = {1,2,3};//Error: assignment to expression with array type
arr[0] = b;//Valid
arr[1] = b + 1;//Valid
b = 5;//Error: assignment of read-only variable 'b'(b is lvalue but not modifiable)
return 0;
}

r-value
هر چی l-value نباشه رو r-value در نظر بگیرید فعلاً تا بینم خدا چی میخواد...
#نکته
#include <stdio.h>
int main()
{
int a = 5;
int b = 12;
printf("reminder of %d divided by %d is %d\n", -b, a, -b % a);
printf("reminder of %d divided by %d is %d\n", b, -a, b % -a);
return 0;
}

خروجی یکسانه؟
https://t.me/ccismywife/16685