Add c-programming-guidelines.md
This commit is contained in:
parent
99af273457
commit
5e2c45fbff
772
c-programming-guidelines.md
Normal file
772
c-programming-guidelines.md
Normal file
@ -0,0 +1,772 @@
|
||||
# C Programming Guidelines
|
||||
|
||||
## 1. Naming Conventions
|
||||
|
||||
### 1.1 Use snake_case for variables and functions
|
||||
- Names should be descriptive but concise
|
||||
- Use lowercase with underscores for separation
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
int user_count = 0;
|
||||
float calculate_average(int *values, int count);
|
||||
char *get_user_input(void);
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
int UserCount = 0; // Uses PascalCase instead of snake_case
|
||||
float calcAvg(int *v, int c); // Unclear abbreviated names
|
||||
char *input(void); // Too vague
|
||||
```
|
||||
|
||||
### 1.2 Use UPPERCASE for constants and macros
|
||||
- All capitals with underscores for separation
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
#define MAX_BUFFER_SIZE 1024
|
||||
#define PI 3.14159
|
||||
const int ERROR_CODE_FILE_NOT_FOUND = -1;
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
#define maxbuffersize 1024 // Should be uppercase with underscores
|
||||
#define Pi 3.14159 // Should be all uppercase
|
||||
const int errorCode = -1; // Should be uppercase with underscores
|
||||
```
|
||||
|
||||
### 1.3 Use PascalCase for types
|
||||
- First letter of each word should be capitalized
|
||||
- This applies to struct, enum, union, and typedef names
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} Point;
|
||||
|
||||
typedef enum {
|
||||
FileStatusOk,
|
||||
FileStatusNotFound,
|
||||
FileStatusPermissionDenied
|
||||
} FileStatus;
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} point; // Should start with capital P
|
||||
|
||||
typedef enum {
|
||||
FILE_STATUS_OK, // Should use PascalCase, not screaming snake case for enum values
|
||||
FILE_STATUS_NOT_FOUND,
|
||||
FILE_STATUS_PERMISSION_DENIED
|
||||
} file_status; // Should start with capital F
|
||||
```
|
||||
|
||||
## 2. Code Formatting
|
||||
|
||||
### 2.1 Use consistent indentation
|
||||
- 4 spaces is the most common choice
|
||||
- Be consistent throughout your project
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
if (condition) {
|
||||
printf("Condition is true\n");
|
||||
if (another_condition) {
|
||||
printf("Both conditions are true\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
if (condition) {
|
||||
printf("Condition is true\n");
|
||||
if (another_condition) {
|
||||
printf("Both conditions are true\n");
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 Use consistent brace style
|
||||
- K&R style (opening brace on same line) is common in C
|
||||
- Whatever style you choose, be consistent
|
||||
|
||||
✅ **Good (K&R style):**
|
||||
```c
|
||||
if (condition) {
|
||||
statement1;
|
||||
statement2;
|
||||
} else {
|
||||
statement3;
|
||||
statement4;
|
||||
}
|
||||
```
|
||||
|
||||
✅ **Also Good (Allman style, if used consistently):**
|
||||
```c
|
||||
if (condition)
|
||||
{
|
||||
statement1;
|
||||
statement2;
|
||||
}
|
||||
else
|
||||
{
|
||||
statement3;
|
||||
statement4;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad (mixing styles):**
|
||||
```c
|
||||
if (condition) {
|
||||
statement1;
|
||||
statement2;
|
||||
}
|
||||
else {
|
||||
statement3;
|
||||
statement4;
|
||||
}
|
||||
```
|
||||
|
||||
### 2.3 Use proper spacing around operators and keywords
|
||||
- Add spaces after commas and around operators
|
||||
- Add space after keywords like if, while, for, but not after function names
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
for (int i = 0; i < 10; i++) {
|
||||
result = calculate(a + b, c * d);
|
||||
if (result > threshold) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
for(int i=0;i<10;i++){
|
||||
result=calculate(a+b,c*d);
|
||||
if(result>threshold){
|
||||
break;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 3. Function Guidelines
|
||||
|
||||
### 3.1 Keep functions short and focused
|
||||
- Each function should have a single responsibility
|
||||
- Aim for 20-30 lines maximum when possible
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
int validate_input(const char *input) {
|
||||
if (input == NULL) {
|
||||
return ERROR_NULL_INPUT;
|
||||
}
|
||||
|
||||
if (strlen(input) > MAX_INPUT_LENGTH) {
|
||||
return ERROR_INPUT_TOO_LONG;
|
||||
}
|
||||
|
||||
if (!contains_valid_chars(input)) {
|
||||
return ERROR_INVALID_CHARS;
|
||||
}
|
||||
|
||||
return INPUT_VALID;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
int process_input(const char *input) {
|
||||
// 100+ lines of code that:
|
||||
// - validates input
|
||||
// - parses input
|
||||
// - processes data
|
||||
// - updates database
|
||||
// - generates report
|
||||
// - handles errors
|
||||
// All mixed together
|
||||
}
|
||||
```
|
||||
|
||||
### 3.2 Use clear parameter names and document function behavior
|
||||
- Input parameters should come first, output parameters last
|
||||
- Use consistent return value semantics
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
/**
|
||||
* Splits a string into tokens based on a delimiter.
|
||||
*
|
||||
* @param str String to tokenize (modified by this function)
|
||||
* @param delim Characters that serve as delimiters
|
||||
* @return Pointer to the next token or NULL if no more tokens found
|
||||
*/
|
||||
char *tokenize_string(char *str, const char *delim) {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// No documentation, unclear parameter names
|
||||
char *ts(char *s, const char *d) {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### 3.3 Check return values and handle errors
|
||||
- Always check return values of functions that can fail
|
||||
- Have explicit error paths
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
FILE *file = fopen("data.txt", "r");
|
||||
if (file == NULL) {
|
||||
fprintf(stderr, "Error opening file: %s\n", strerror(errno));
|
||||
return ERROR_FILE_OPEN_FAILED;
|
||||
}
|
||||
|
||||
// Use the file
|
||||
|
||||
fclose(file);
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
FILE *file = fopen("data.txt", "r");
|
||||
// No error checking!
|
||||
|
||||
// Use the file - potential NULL pointer dereference
|
||||
|
||||
fclose(file);
|
||||
```
|
||||
|
||||
## 4. Memory Management
|
||||
|
||||
### 4.1 Always pair allocation with deallocation
|
||||
- Every `malloc()` needs a matching `free()`
|
||||
- Check for allocation failures
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
int *data = (int *)malloc(size * sizeof(int));
|
||||
if (data == NULL) {
|
||||
fprintf(stderr, "Memory allocation failed\n");
|
||||
return ERROR_MEMORY_ALLOCATION;
|
||||
}
|
||||
|
||||
// Use the allocated memory
|
||||
|
||||
free(data);
|
||||
data = NULL; // Prevent use after free
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
int *data = (int *)malloc(size * sizeof(int));
|
||||
// No NULL check!
|
||||
|
||||
// Use the allocated memory
|
||||
|
||||
// No free - memory leak!
|
||||
```
|
||||
|
||||
### 4.2 Use consistent resource management patterns
|
||||
- Release resources in reverse order of acquisition
|
||||
- Consider using goto for error cleanup in C
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
int process_data(void) {
|
||||
FILE *input_file = NULL;
|
||||
FILE *output_file = NULL;
|
||||
char *buffer = NULL;
|
||||
int result = SUCCESS;
|
||||
|
||||
buffer = (char *)malloc(BUFFER_SIZE);
|
||||
if (buffer == NULL) {
|
||||
result = ERROR_MEMORY_ALLOCATION;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
input_file = fopen("input.txt", "r");
|
||||
if (input_file == NULL) {
|
||||
result = ERROR_INPUT_FILE_OPEN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
output_file = fopen("output.txt", "w");
|
||||
if (output_file == NULL) {
|
||||
result = ERROR_OUTPUT_FILE_OPEN;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
// Process data using all resources
|
||||
|
||||
cleanup:
|
||||
// Clean up in reverse order
|
||||
if (output_file != NULL) fclose(output_file);
|
||||
if (input_file != NULL) fclose(input_file);
|
||||
free(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
int process_data(void) {
|
||||
// Inconsistent error handling and resource cleanup
|
||||
char *buffer = (char *)malloc(BUFFER_SIZE);
|
||||
FILE *input_file = fopen("input.txt", "r");
|
||||
|
||||
if (input_file == NULL) {
|
||||
free(buffer);
|
||||
return ERROR_INPUT_FILE_OPEN;
|
||||
}
|
||||
|
||||
FILE *output_file = fopen("output.txt", "w");
|
||||
// Forgot to check if output_file is NULL
|
||||
|
||||
// Process data
|
||||
|
||||
fclose(input_file);
|
||||
fclose(output_file); // Might be NULL!
|
||||
// Forgot to free buffer - memory leak!
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Header Files
|
||||
|
||||
### 5.1 Always use include guards
|
||||
- Prevent multiple inclusion with include guards
|
||||
- Use a unique name based on file path
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
#ifndef PROJECT_MODULE_HEADER_H
|
||||
#define PROJECT_MODULE_HEADER_H
|
||||
|
||||
// Header content
|
||||
|
||||
#endif /* PROJECT_MODULE_HEADER_H */
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// No include guard - can cause multiple definition errors
|
||||
|
||||
typedef struct {
|
||||
int x;
|
||||
int y;
|
||||
} Point;
|
||||
|
||||
void draw_point(Point p);
|
||||
```
|
||||
|
||||
### 5.2 Organize includes consistently
|
||||
- Include system headers first, then project headers
|
||||
- Group related declarations
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
/* System includes */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
/* Project includes */
|
||||
#include "project/common.h"
|
||||
#include "project/utils.h"
|
||||
|
||||
/* Module-specific includes */
|
||||
#include "module/internal.h"
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
#include "module/internal.h"
|
||||
#include <string.h>
|
||||
#include "project/common.h"
|
||||
#include <stdio.h>
|
||||
#include "project/utils.h"
|
||||
#include <stdlib.h>
|
||||
```
|
||||
|
||||
### 5.3 Declare what you use, use what you declare
|
||||
- Include only what you need
|
||||
- Don't rely on indirect includes
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
// In file.h
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include <stddef.h> // For size_t
|
||||
|
||||
// Declare only what other modules need
|
||||
size_t read_file(const char *filename, char *buffer, size_t buffer_size);
|
||||
|
||||
#endif /* FILE_H */
|
||||
|
||||
// In file.c
|
||||
#include "file.h"
|
||||
#include <stdio.h> // For FILE, fopen, etc.
|
||||
#include <string.h> // For strerror
|
||||
|
||||
size_t read_file(const char *filename, char *buffer, size_t buffer_size) {
|
||||
// Implementation using stdio functions
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// In file.h
|
||||
#ifndef FILE_H
|
||||
#define FILE_H
|
||||
|
||||
#include <stdio.h> // Exposing implementation details
|
||||
#include <string.h> // Not needed in the interface
|
||||
#include <stdlib.h> // Not needed in the interface
|
||||
|
||||
// Using stdio in the interface
|
||||
FILE *open_file(const char *filename);
|
||||
size_t read_file(FILE *file, char *buffer, size_t buffer_size);
|
||||
|
||||
#endif /* FILE_H */
|
||||
```
|
||||
|
||||
## 6. Comments and Documentation
|
||||
|
||||
### 6.1 Document function interfaces
|
||||
- Describe purpose, parameters, return values, and side effects
|
||||
- Document error conditions
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
/**
|
||||
* Searches for a substring within a string.
|
||||
*
|
||||
* @param haystack The string to search in
|
||||
* @param needle The substring to search for
|
||||
* @return Pointer to the first occurrence of needle in haystack,
|
||||
* or NULL if needle is not found
|
||||
*/
|
||||
char *find_substring(const char *haystack, const char *needle) {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// Finds a string
|
||||
char *find_substring(const char *s1, const char *s2) {
|
||||
// Implementation
|
||||
}
|
||||
```
|
||||
|
||||
### 6.2 Comment complex or non-obvious code
|
||||
- Explain the "why" not the "what"
|
||||
- Keep comments up to date with code changes
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
// Use binary search to find insertion point while maintaining ordering
|
||||
// This is O(log n) rather than the O(n) approach of linear search
|
||||
int insertion_index = find_insertion_point(array, value, 0, array_size - 1);
|
||||
|
||||
// Special case: The XDR protocol requires 4-byte alignment for data
|
||||
// so we pad the buffer with zeros as needed
|
||||
size_t padding = (4 - (buffer_size % 4)) % 4;
|
||||
memset(buffer + buffer_size, 0, padding);
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// This function finds the substring
|
||||
char *p = strstr(s, sub);
|
||||
|
||||
// Increment i
|
||||
i++;
|
||||
|
||||
// Too much detail about "what" the code does, not "why"
|
||||
// Loop through the array and add each element to sum
|
||||
int sum = 0;
|
||||
for (int i = 0; i < size; i++) {
|
||||
sum += array[i]; // Add element to sum
|
||||
}
|
||||
```
|
||||
|
||||
## 7. Error Handling
|
||||
|
||||
### 7.1 Use consistent error reporting
|
||||
- Choose one approach (return codes, errno, error objects) and stick with it
|
||||
- Document error codes
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
/**
|
||||
* Error codes for the file module
|
||||
*/
|
||||
#define FILE_ERROR_NONE 0
|
||||
#define FILE_ERROR_NOT_FOUND -1
|
||||
#define FILE_ERROR_PERMISSION -2
|
||||
#define FILE_ERROR_INVALID_FORMAT -3
|
||||
|
||||
/**
|
||||
* Opens a configuration file and validates its format.
|
||||
*
|
||||
* @param filename The path to the config file
|
||||
* @return FILE_ERROR_NONE on success, or appropriate error code on failure
|
||||
*/
|
||||
int open_config_file(const char *filename) {
|
||||
if (access(filename, F_OK) != 0) {
|
||||
return FILE_ERROR_NOT_FOUND;
|
||||
}
|
||||
|
||||
if (access(filename, R_OK) != 0) {
|
||||
return FILE_ERROR_PERMISSION;
|
||||
}
|
||||
|
||||
// Check file format
|
||||
if (!is_valid_config_format(filename)) {
|
||||
return FILE_ERROR_INVALID_FORMAT;
|
||||
}
|
||||
|
||||
return FILE_ERROR_NONE;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// Inconsistent error reporting
|
||||
int open_file(const char *filename) {
|
||||
FILE *file = fopen(filename, "r");
|
||||
if (file == NULL) {
|
||||
printf("Error opening file\n");
|
||||
return -1; // Generic error code
|
||||
}
|
||||
|
||||
if (!is_valid_format(file)) {
|
||||
fprintf(stderr, "Invalid format\n");
|
||||
fclose(file);
|
||||
exit(1); // Abrupt program termination!
|
||||
}
|
||||
|
||||
// No error, but doesn't return the file handle!
|
||||
fclose(file);
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 7.2 Validate function inputs
|
||||
- Check parameters for validity at the beginning of functions
|
||||
- Return early for invalid inputs
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
int calculate_average(const int *values, size_t count, double *result) {
|
||||
// Validate inputs
|
||||
if (values == NULL || result == NULL) {
|
||||
return ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
if (count == 0) {
|
||||
return ERROR_DIVISION_BY_ZERO;
|
||||
}
|
||||
|
||||
// Calculation is safe now
|
||||
double sum = 0;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
sum += values[i];
|
||||
}
|
||||
|
||||
*result = sum / count;
|
||||
return SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
double calculate_average(int *values, int count) {
|
||||
// No input validation!
|
||||
|
||||
double sum = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
sum += values[i]; // Potential NULL pointer dereference!
|
||||
}
|
||||
|
||||
return sum / count; // Potential division by zero!
|
||||
}
|
||||
```
|
||||
|
||||
## 8. Defensive Programming
|
||||
|
||||
### 8.1 Check array bounds
|
||||
- Never access arrays out of bounds
|
||||
- Use size parameters to track array sizes
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
/**
|
||||
* Finds the maximum value in an array.
|
||||
*/
|
||||
int find_maximum(const int *array, size_t size) {
|
||||
if (array == NULL || size == 0) {
|
||||
return INT_MIN; // Error value
|
||||
}
|
||||
|
||||
int max = array[0];
|
||||
for (size_t i = 1; i < size; i++) {
|
||||
if (array[i] > max) {
|
||||
max = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
int find_maximum(int *array, int size) {
|
||||
// No validation on array or size
|
||||
|
||||
int max = array[0]; // Crash if array is NULL or size is 0
|
||||
|
||||
// Could go out of bounds if size is incorrect
|
||||
for (int i = 1; i <= size; i++) { // Note: <= is wrong!
|
||||
if (array[i] > max) {
|
||||
max = array[i];
|
||||
}
|
||||
}
|
||||
|
||||
return max;
|
||||
}
|
||||
```
|
||||
|
||||
### 8.2 Initialize variables before use
|
||||
- Always initialize variables
|
||||
- Don't rely on default initialization
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
void process_data(void) {
|
||||
int count = 0;
|
||||
double total = 0.0;
|
||||
char buffer[MAX_SIZE] = {0}; // Zero-initialize array
|
||||
|
||||
// Variables are initialized before use
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
void process_data(void) {
|
||||
int count; // Uninitialized
|
||||
double total; // Uninitialized
|
||||
char buffer[MAX_SIZE]; // Uninitialized
|
||||
|
||||
// Using variables without initialization
|
||||
total = total + 10.0; // Undefined behavior
|
||||
}
|
||||
```
|
||||
|
||||
## 9. Performance Considerations
|
||||
|
||||
### 9.1 Prefer readability unless performance is critical
|
||||
- Write clear, readable code first
|
||||
- Optimize only when necessary and based on profiling
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
// Clear and readable implementation
|
||||
double calculate_average(const int *values, size_t count) {
|
||||
if (values == NULL || count == 0) {
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
double sum = 0.0;
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
sum += values[i];
|
||||
}
|
||||
|
||||
return sum / count;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad (premature optimization):**
|
||||
```c
|
||||
// Trying to be clever with unnecessary optimization
|
||||
double calculate_average(const int *values, size_t count) {
|
||||
if (!values || !count) return 0.0;
|
||||
|
||||
register double sum = 0.0; // 'register' rarely helps modern compilers
|
||||
register size_t i = count;
|
||||
|
||||
// Reversed loop for "performance" but harder to understand
|
||||
while (i--) {
|
||||
sum += values[i];
|
||||
}
|
||||
|
||||
return sum / count;
|
||||
}
|
||||
```
|
||||
|
||||
### 9.2 Document performance-critical code
|
||||
- Explain the reasoning behind optimization
|
||||
- Note any assumptions that affect performance
|
||||
|
||||
✅ **Good:**
|
||||
```c
|
||||
/**
|
||||
* Fast string hash function optimized for short strings.
|
||||
* Uses FNV-1a algorithm which has good distribution and
|
||||
* is quick for strings under 100 bytes.
|
||||
*
|
||||
* Time complexity: O(n) where n is string length
|
||||
* Performance assumption: Most strings are under 20 chars
|
||||
*/
|
||||
unsigned int hash_string(const char *str) {
|
||||
const unsigned int FNV_PRIME = 16777619;
|
||||
const unsigned int FNV_OFFSET_BASIS = 2166136261;
|
||||
|
||||
unsigned int hash = FNV_OFFSET_BASIS;
|
||||
|
||||
while (*str) {
|
||||
hash ^= (unsigned char)*str++;
|
||||
hash *= FNV_PRIME;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
```
|
||||
|
||||
❌ **Bad:**
|
||||
```c
|
||||
// No documentation of algorithm choice or performance characteristics
|
||||
unsigned int hash_string(const char *str) {
|
||||
unsigned int hash = 2166136261;
|
||||
|
||||
while (*str) {
|
||||
hash ^= (unsigned char)*str++;
|
||||
hash *= 16777619;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
```
|
||||
Loading…
x
Reference in New Issue
Block a user