c - সি ভাষার প্রোগ্রামের গঠন




আপনার প্রিয় সি প্রোগ্রামিং কৌশল কি? (20)

C99 বেনামী অ্যারে ব্যবহার করে কিছু সত্যিই শীতল উপাদান প্রস্তাব:

বিন্দুহীন পরিবর্তনশীল অপসারণ

{
    int yes=1;
    setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(int));
}

হয়ে

setsockopt(yourSocket, SOL_SOCKET, SO_REUSEADDR, (int[]){1}, sizeof(int));

আর্গুমেন্ট একটি পরিবর্তনশীল পরিমাণ পাস

void func(type* values) {
    while(*values) {
        x = *values++;
        /* do whatever with x */
    }
}

func((type[]){val1,val2,val3,val4,0});

স্ট্যাটিক লিঙ্ক তালিকা

int main() {
    struct llist { int a; struct llist* next;};
    #define cons(x,y) (struct llist[]){{x,y}}
    struct llist *list=cons(1, cons(2, cons(3, cons(4, NULL))));
    struct llist *p = list;
    while(p != 0) {
        printf("%d\n", p->a);
        p = p->next;
    }
}

আমি যে কোনও অন্যান্য দুর্দান্ত কৌশল সম্পর্কে নিশ্চিত নই।

উদাহরণস্বরূপ, আমি সম্প্রতি লিনাক্স কার্নেল এ এটি জুড়েছি:

/* Force a compilation error if condition is true */
#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

সুতরাং, আপনার কোডটিতে যদি আপনার কিছু কাঠামো থাকা উচিত তবে আকারে 8 বাইটের একাধিকটি বলুন, সম্ভবত কিছু হার্ডওয়্যার সীমাবদ্ধতার কারণে আপনি এটি করতে পারেন:

BUILD_BUG_ON((sizeof(struct mystruct) % 8) != 0);

এবং সংকলন মাইটস্ট্রাকের আকারটি 8 এর একাধিক না হওয়া পর্যন্ত সংকলন করা হবে না এবং যদি এটি 8 এর একাধিক হয় তবে কোনও রানটাইম কোড উত্পন্ন হয় না।

আরেকটি কৌশল আমি জানি "গ্রাফিক্স জেমস" বইটি যা এক মডিউল ফাইলকে মডিউল ব্যবহার করে অন্য মডিউলগুলিতে ঘোষণা করে এবং একটি মডিউলে ভেরিয়েবলগুলিকে আরম্ভ করতে দেয়, কেবল তাদের বহির্মুখ হিসাবে ঘোষণা করে।

#ifdef DEFINE_MYHEADER_GLOBALS
#define GLOBAL
#define INIT(x, y) (x) = (y)
#else
#define GLOBAL extern
#define INIT(x, y)
#endif

GLOBAL int INIT(x, 0);
GLOBAL int somefunc(int a, int b);

এর সাথে, x এবং somefunc সংজ্ঞায়িত করে এমন কোডটি করে:

#define DEFINE_MYHEADER_GLOBALS
#include "the_above_header_file.h"

যখন কোডটি কেবল x এবং somefunc () ব্যবহার করে থাকে:

#include "the_above_header_file.h"

সুতরাং আপনি একটি শিরোনাম ফাইল পাবেন যা গ্লোবাল এবং ফাংশন প্রোটোটাইপের উভয় উদাহরণগুলি যেখানে তাদের প্রয়োজন হয় এবং ঘোষণা সম্পর্কিত এক্সটার্ন ঘোষণাগুলি ঘোষণা করে।

সুতরাং, ঐ লাইন বরাবর আপনার প্রিয় সি প্রোগ্রামিং কৌশল কি?


অ্যাপ্লিকেশনটি চালানোর জন্য আসলে HW কী ব্যবহার করা হয় সে সম্পর্কে সি কোডটি সম্পূর্ণরূপে অজানা কিভাবে একটি উদাহরণ এখানে। Main.c সেটআপ করে এবং তারপর বিনামূল্যে স্তর কোন কম্পাইলার / খিলান উপর প্রয়োগ করা যেতে পারে। আমি মনে করি সি কোডটি বিমূর্ত করার জন্য এটি বেশ পরিষ্কার, তাই এটি স্পেসিফিকেশন হতে পারে না।

এখানে একটি সম্পূর্ণ সংহত উদাহরণ যোগ করা হচ্ছে।

/* free.h */
#ifndef _FREE_H_
#define _FREE_H_
#include <stdio.h>
#include <string.h>
typedef unsigned char ubyte;

typedef void (*F_ParameterlessFunction)() ;
typedef void (*F_CommandFunction)(ubyte byte) ;

void F_SetupLowerLayer (
F_ParameterlessFunction initRequest,
F_CommandFunction sending_command,
F_CommandFunction *receiving_command);
#endif

/* free.c */
static F_ParameterlessFunction Init_Lower_Layer = NULL;
static F_CommandFunction Send_Command = NULL;
static ubyte init = 0;
void recieve_value(ubyte my_input)
{
    if(init == 0)
    {
        Init_Lower_Layer();
        init = 1;
    }
    printf("Receiving 0x%02x\n",my_input);
    Send_Command(++my_input);
}

void F_SetupLowerLayer (
    F_ParameterlessFunction initRequest,
    F_CommandFunction sending_command,
    F_CommandFunction *receiving_command)
{
    Init_Lower_Layer = initRequest;
    Send_Command = sending_command;
    *receiving_command = &recieve_value;
}

/* main.c */
int my_hw_do_init()
{
    printf("Doing HW init\n");
    return 0;
}
int my_hw_do_sending(ubyte send_this)
{
    printf("doing HW sending 0x%02x\n",send_this);
    return 0;
}
F_CommandFunction my_hw_send_to_read = NULL;

int main (void)
{
    ubyte rx = 0x40;
    F_SetupLowerLayer(my_hw_do_init,my_hw_do_sending,&my_hw_send_to_read);

    my_hw_send_to_read(rx);
    getchar();
    return 0;
}

আমাদের কোডবেস অনুরূপ একটি কৌতুক আছে

#ifdef DEBUG

#define my_malloc(amt) my_malloc_debug(amt, __FILE__, __LINE__)
void * my_malloc_debug(int amt, char* file, int line)
#else
void * my_malloc(int amt)
#endif
{
    //remember file and line no. for this malloc in debug mode
}

যা ডিবাগ মোডে মেমরি লিকের ট্র্যাকিংয়ের জন্য অনুমতি দেয়। আমি সবসময় এই শান্ত ছিল।


আমি = {0}; ব্যবহার করে ভালোবাসি = {0}; স্মৃতি কল কল ছাড়া কাঠামো আরম্ভ করতে।

struct something X = {0};

এটি স্ট্রাক্টের সকল সদস্যদের শূন্যে (বা অ্যারে) শুরুর দিকে শুরু করবে (তবে কোন প্যাডিং বাইট নয় - যদি আপনি সেগুলি শূন্য করতে চান তবে স্মৃতি ব্যবহার করুন)।

তবে সচেতন হওয়া উচিত যে এটির সাথে বড়, গতিশীলভাবে বরাদ্দকৃত কাঠামোর জন্য কিছু সমস্যা রয়েছে


আমি xor হ্যাক একটি ফ্যান:

তৃতীয় temp পয়েন্টার ছাড়া 2 পয়েন্টার Swap:

int * a;
int * b;
a ^= b;
b ^= a;
a ^= b;

অথবা আমি সত্যিই এক পয়েন্টার সঙ্গে xor লিঙ্ক তালিকা পছন্দ। (Http://en.wikipedia.org/wiki/XOR_linked_list)

লিঙ্ক তালিকা প্রতিটি নোড পূর্ববর্তী নোড এবং পরবর্তী নোড এর Xor হয়। অগ্রসর হওয়ার জন্য, নোডের ঠিকানা নিম্নলিখিত পদ্ধতিতে পাওয়া যায়:

LLNode * first = head;
LLNode * second = first.linked_nodes;
LLNode * third = second.linked_nodes ^ first;
LLNode * fourth = third.linked_nodes ^ second;

প্রভৃতি

অথবা পিছনে দিকে তাকাতে:

LLNode * last = tail;
LLNode * second_to_last = last.linked_nodes;
LLNode * third_to_last = second_to_last.linked_nodes ^ last;
LLNode * fourth_to_last = third_to_last.linked_nodes ^ second_to_last;

প্রভৃতি

যদিও খুব দরকারী না (আপনি একটি নির্বিচারে নোড থেকে ট্রান্সক্রসিং শুরু করতে পারবেন না) আমি খুব শান্ত হতে এটি।


আমি একটি গতিশীল আকারের বস্তু থাকার জন্য "গঠন হ্যাক" পছন্দ। এই সাইটটি এটি খুব ভালভাবে ব্যাখ্যা করে (যদিও তারা C99 সংস্করণটি উল্লেখ করে যেখানে আপনি "str []" লিখতে পারেন একটি struct এর শেষ সদস্য হিসাবে)। আপনি এই মত একটি স্ট্রিং "বস্তু" করতে পারে:

struct X {
    int len;
    char str[1];
};

int n = strlen("hello world");
struct X *string = malloc(sizeof(struct X) + n);
strcpy(string->str, "hello world");
string->len = n;

এখানে, আমরা হিপের টাইপ X এর কাঠামো বরাদ্দ করেছি যা একটি int (আকারের জন্য), এবং প্লাস 1 "হ্যালো ওয়ার্ল্ড" এর দৈর্ঘ্য, প্লাস 1 (যেহেতু স্ট্র 1 সাইফফ (X) তে অন্তর্ভুক্ত।

একই ব্লকের কিছু পরিবর্তনশীল দৈর্ঘ্য ডেটা আগে আপনি "শিরোনাম" পেতে চাইলে এটি সাধারণত দরকারী।


আমি প্রাক-কম্পাইলার কোড জেনারেট করার জন্য X-Macros ব্যবহার করি। তারা বিশেষ করে ত্রুটির মানগুলি এবং সংশ্লিষ্ট ত্রুটির স্ট্রিংগুলিকে এক জায়গায় সংজ্ঞায়িত করার জন্য উপকারী, তবে তারা এটির থেকে অনেক দূরে যেতে পারে।


আমি সত্যিই এটি একটি প্রিয় কৌতুক বলব না, যেহেতু আমি এটি ব্যবহার করিনি, তবে ডাফের ডিভাইসের উল্লেখটি আমাকে সি-তে Coroutines বাস্তবায়ন সম্পর্কে এই নিবন্ধটি মনে করিয়ে দিয়েছে। এটি আমাকে সবসময় চকলেট দেয়, তবে আমি নিশ্চিত যে এটি কিছু সময় দরকারী হতে হবে।


এই ধরণের জিনিসগুলির জন্য দুটি ভাল উৎস বইগুলি প্রোগ্রামিং এবং প্রলিটিং সলিড কোডের অনুশীলন । তাদের মধ্যে একজন (আমি মনে রাখি না) বলছেন: # যেখানে আপনি করতে পারেন Enum পছন্দ করুন, কারণ enum কম্পাইলার দ্বারা চেক পায়।


এই বইটি 'যথেষ্ট দড়ি থেকে শ্যুট নিজেকে নিজের পায়ে' বই থেকে এসেছে:

হেডার ঘোষণা

#ifndef RELEASE
#  define D(x) do { x; } while (0)
#else
#  define D(x)
#endif

আপনার কোড জায়গায় পরীক্ষার বিবৃতি যেমন:

D(printf("Test statement\n"));

ম্যাক্রোর বিষয়বস্তু একাধিক বিবৃতিতে প্রসারিত হলে ক্ষেত্রে / সময় সহায়তা করে।

কম্পাইলারের জন্য '-ড রিলিজ' পতাকা ব্যবহার করা হয় না শুধুমাত্র বিবৃতিটি মুদ্রণ করা হবে।

আপনি তারপর যেমন পারেন। আপনার makefile ইত্যাদিতে পতাকা পাস করুন।

এই উইন্ডোতে কাজ কিভাবে নিশ্চিত না কিন্তু * nix এটি ভাল কাজ করে


এমন একটি পরিবর্তনশীল তৈরির জন্য যা শুধুমাত্র মডিউলে পাঠযোগ্য কেবলমাত্র এটির মধ্যে ঘোষণা করা হয়:

// Header1.h:

#ifndef SOURCE1_C
   extern const int MyVar;
#endif
// Source1.c:

#define SOURCE1_C
#include Header1.h // MyVar isn't seen in the header

int MyVar; // Declared in this file, and is writeable
// Source2.c

#include Header1.h // MyVar is seen as a constant, declared elsewhere

কোয়েক 2 সোর্স কোড পড়ার সময় আমি এইরকম কিছু নিয়ে এসেছি:

double normals[][] = {
  #include "normals.txt"
};

(আরো বা কম, আমার কোডটি এখন চেক করার জন্য এটি কার্যকর নয়)।

তারপরে, আমার চোখের সামনে প্রিপ্রোসেসার সৃজনশীল ব্যবহারের একটি নতুন জগৎ খোলা আছে। আমি আর শিরোনামগুলি অন্তর্ভুক্ত করি না, তবে এখন কোডের পুরো অংশগুলি এবং তারপরে (এটি পুনঃব্যবহারযোগ্যতাকে অনেকগুলি উন্নত করে): -p

ধন্যবাদ জন Carmack! xD


ডিবাগিংয়ের জন্য __FILE__ এবং __LINE__ ব্যবহার করে

#define WHERE fprintf(stderr,"[LOG]%s:%d\n",__FILE__,__LINE__);

পরিবর্তে

printf("counter=%d\n",counter);

ব্যবহার

#define print_dec(var)  printf("%s=%d\n",#var,var);
print_dec(counter);

মরিচা আসলে ক ccan মধ্যে বিল্ড শর্তাবলী একটি সম্পূর্ণ সেট উত্পাদিত, নির্মাণ ccan মডিউল দেখুন:

#include <stddef.h>
#include <ccan/build_assert/build_assert.h>

struct foo {
        char string[5];
        int x;
};

char *foo_string(struct foo *foo)
{
        // This trick requires that the string be first in the structure
        BUILD_ASSERT(offsetof(struct foo, string) == 0);
        return (char *)foo;
}

প্রকৃত হেডারের অন্যান্য সহায়ক ম্যাক্রো রয়েছে যা সহজে স্থানান্তরিত হয়।

বেশিরভাগই ইনলাইন ফাংশনে স্টিক করে অন্ধকার পার্শ্ব (এবং প্রিপপ্রসেসার অপব্যবহার) এর টানটিকে প্রতিরোধ করার আমার সমস্ত শক্তি দিয়ে আমি চেষ্টা করি, কিন্তু আপনি বর্ণিত মত চকচকে, কার্যকর ম্যাক্রোগুলি উপভোগ করেন।


ম্যাক্রো সঙ্গে মজা:

#define SOME_ENUMS(F) \
    F(ZERO, zero) \
    F(ONE, one) \
    F(TWO, two)

/* Now define the constant values.  See how succinct this is. */

enum Constants {
#define DEFINE_ENUM(A, B) A,
    SOME_ENUMS(DEFINE_ENUMS)
#undef DEFINE_ENUM
};

/* Now a function to return the name of an enum: */

const char *ToString(int c) {
    switch (c) {
    default: return NULL; /* Or whatever. */
#define CASE_MACRO(A, B) case A: return #b;
     SOME_ENUMS(CASE_MACRO)
#undef CASE_MACRO
     }
}

সি 99

typedef struct{
    int value;
    int otherValue;
} s;

s test = {.value = 15, .otherValue = 16};

/* or */
int a[100] = {1,2,[50]=3,4,5,[23]=6,7};

সি নির্দিষ্ট নয়, কিন্তু আমি সবসময় এক্সওআর অপারেটর পছন্দ করেছি। এটি করতে পারেন একটি শীতল জিনিস "একটি temp মান ছাড়া স্ন্যাপ" হয়:

int a = 1;
int b = 2;

printf("a = %d, b = %d\n", a, b);

a ^= b;
b ^= a;
a ^= b;

printf("a = %d, b = %d\n", a, b);

ফলাফল:

একটি = 1, বি = 2

একটি = 2, বি = 1



#if TESTMODE == 1    
    debug=1;
    while(0);     // Get attention
#endif

সময় (0); প্রোগ্রামটির উপর কোন প্রভাব নেই, তবে কম্পাইলার "এইটি কিছুই করে না" সম্পর্কে একটি সতর্কতা জারি করবে, যা আমাকে আক্রমণাত্মক লাইনটি দেখার জন্য যথেষ্ট এবং তারপর আসল কারণটি আমি তার দিকে মনোযোগ দিতে চেয়েছি।





c